0
#include <stdio.h>
#include <stdlib.h>

struct student
{
    char name[30];
    char dob[30];
    int rollno;
    float percent;
    int sub[3];
    int total;
};

int main(void)
{
    int i, n,a,c,*ptr;
    char ch;
    struct student *st;
    
    printf("Enter number of students data you want to enter:\n");
    scanf("%d",&n);

    st=(struct student*) malloc(n * sizeof(struct student));

    if(st == NULL) 
    {
        printf("Error! memory not allocated.");
        exit(0);
    }

    for(i=1;i <= n;i++)
    {
        printf("Enter name of student %d\n",(i));
        scanf("%s",&(st+i)->name);
        printf("Enter Roll No of student %d\n",(i));
        scanf("%d",&(st+i)->rollno);
        printf("Enter Date Of Birth of student %d\n",(i));
        scanf("%s",&(st+i)->dob);
        printf("Enter marks for 3 subjects of student %d\n",(i));
        scanf("%d %d %d",&(st+i)->sub[0],&(st+i)->sub[1],&(st+i)->sub[2]);
        (st+i)->total = ((st+i)->sub[0]+(st+i)->sub[1]+(st+i)->sub[2]);
        printf("Total Marks of student %d = %d\n\n",(i), (st+i)->total);
    }
    printf("\n");

    printf("\n<1>To display details of students\n");
    printf("\n<2>exit\n");
    printf("Enter your choice:\n");
    scanf("%c",&ch);

    switch(ch)
    {
    case '1':
    {      
        for(i=1; i <= n;i++)
        { 
            printf("\n%d.%s",(st+i)->rollno,(st+i)->name);
        }

        printf("\n Enter Roll no to display info of student");
        scanf("%d",&a);

        {
            c=a;
            a=i;
            i=c;

        if((st+i)->sub[0]<33||(st+i)->sub[1]<33||(st+i)->sub[2]<33)
        {   
            printf("\nName of student: %s",(st+i)->name);
            printf("\nRoll No of student: %d",(st+i)->rollno);
            printf("\nDate of Birth : %s",(st+i)->dob);
            printf("\nTotal of student: %d",(st+i)->total);
            printf("\nStudent Status fail");
            return 0;
        }

        printf("\nName of student: %s",(st+i)->name);
        printf("\nRoll No of student: %d",(st+i)->rollno);
        printf("\nDate of Birth : %s",(st+i)->dob);
        printf("\nTotal of student: %d",(st+i)->total);

        (st+i)->percent=((st+i)->total)/3;

        printf("\nPercent of Student = %f",(st+i)->percent);

        if((st+i)->percent>=33)
        {
            printf("\nStudent status:- PASS\n");
        }
        else
            printf("\nStudent status:-FAIL\n");

        if((st+i)->percent>=90)
            printf("Grade= A1\n");
        else if (80<=(st+i)->percent)
            printf("Grade= A2\n");
        else if(70<=(st+i)->percent)
            printf("Grade= B1\n");
        else if(60<=(st+i)->percent)
            printf("Grade= B2\n");
        else if(50<=(st+i)->percent)
            printf("Grade= C1\n");
        else if(40<=(st+i)->percent)
            printf("Grade= C2\n");
        else if(33<=(st+i)->percent)
            printf("Grade= D\n");
        else if((st+i)->percent<33)
            printf("Grade= F\n");
        }

        break;
    }

    case '2':
    {
        return 0;
    }

    default:
        printf("Invalid! Try again...\n");
    }

    free(st);
    return 0;
}

I want my program to take input of various details of students and display them when I enter the roll no. of student. However, the switch statement is not executing; the program just exits after taking input. I checked syntax, but it's correct I don't know what the issue is. If I could get a hint about the issue it would be great.

Yun
  • 3,056
  • 6
  • 9
  • 28
  • 2
    Your loop is `for(i=1;i <= n;i++)` but arrays are indexed from `0`. So `&(st+i)` is off-by-one element and the final iteration will break the memory allocation. – Weather Vane Sep 01 '21 at 11:40
  • Aside: `scanf("%c",&ch);` should be `scanf(" %c",&ch);` with that added space to filter the previous newline left in the buffer. Please see [scanf() leaves the newline char in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer). – Weather Vane Sep 01 '21 at 11:44
  • @WeatherVane I corrected scanf(" %c",&ch): and the code is working now but I didn't get that array indexing error if you could elaborate that would be a great help. – Someonesomebody Sep 01 '21 at 11:54
  • 1
    The off-by-one indexing means you have ignored the first `struct` in the array, and in the final iteration attempted to use a `struct` beyond the end of the allocated memory. So the inputs have clobbered something, resulting in a possible program crash, or magically still working. It is undefined what will happen, but [Finagle's Law](https://en.wikipedia.org/wiki/Finagle%27s_law) states that the crash will occur when you make your class presentation. – Weather Vane Sep 01 '21 at 11:57
  • 2
    @WeatherVane so I should start with i=0 till i – Someonesomebody Sep 01 '21 at 12:02

2 Answers2

1

The problem has nothing to do with the switch statement, but with writing to and reading from to correct memory locations.

In C, arrays start at index 0. Therefore, the first for-loop tries to access memory outside of what is allocated. The idiomatic solution is to start i at 0 and loop while it is strictly less than the size of the array.

Pointer arithmetic not needed here for accessing the array members, and is better replaced by the index operators ([]). More importantly, please have careful look at the types scanf expects and the actual types of the parameters. The name and dob variables are already of the type char* (or char[30] with pointer decay), so they do not need an additional "address of" operator (&). Viewing the compiler warnings helps in catching these kind of errors.

Here is the code with the suggested improvements:

for(i=0;i < n;i++)
{
    printf("Enter name of student %d\n",(i));
    scanf("%s",st[i].name);
    printf("Enter Roll No of student %d\n",(i));
    scanf("%d",&st[i].rollno);
    printf("Enter Date Of Birth of student %d\n",(i));
    scanf("%s",st[i].dob);
    // ...

With this resolved, the code now skips past the switch menu because there already is a newline character (\n) in the input which is read by scanf. To skip over leading whitespace (which includes newline characters), add a space character ( ) before the character conversion specifier:

scanf(" %c",&ch);

Inside the switch statement, apply the same fix as earlier to the for-loop:

for(i=0; i < n;i++)

What follows are more invalid reads, probably caused by c=a; a=i; i=c; and I am not sure what the idea behind this is.
Instead of fixing the entire program, I hope that the advice above will help you on your way to resolving the other issues yourself. It may help to write short isolated code snippets first and fully test these (e.g. by writing to certain memory and then reading from it) and afterwards incorporating these snippets into a larger program. Also, compiling with debug info (the -g flag) and running the program with Valgrind may help you track down where the bugs come from.

Lastly, by careful of using scanf to read strings. Currently, it may cause buffer overflows if the input string is longer than the size of the array written to. Use, e.g., scanf("%29s",st[i].name); to limit the maximum number of characters scanf will read. There is more to reading input safely and predictably than I can write here, so I encourage you to look around on Stack Overflow or elsewhere yourself.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
Yun
  • 3,056
  • 6
  • 9
  • 28
0

use getchar() instead of scanf(). This is because scanf leaves the newline you type in the input stream. Try

do
   ch = getchar();
while (isspace(ch));
harry
  • 970
  • 6
  • 25
  • 1
    Better to correctly use `scanf` and not to mix the input methods, which often results in a 'kludge' solution. – Weather Vane Sep 01 '21 at 11:49
  • 1
    This fails to recognize an `EOF` returned from `getchar`, both because it does not test for it and because `ch` is declared `char` and hence cannot be expected to represent `EOF`. – Eric Postpischil Sep 01 '21 at 11:50