Why does my program end after the last scanf?

61 Views Asked by At

I am writing a program with structs and pointers. As you will see in the program I am asking the user if he wants to continue adding students. And I want to check if his answer is Yes or No. Obviously I am doing something wrong because my program finishes after his answer. So I want help to spot the bug and to find a way to write the code correctly.

Also I want to ask why number[i].age needs an & in font of it in scanf. I mean it is a pointer so why use a &?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student {

  char name[30];
  int age;

}student ;

int main(){
 typedef int size;
 int i;
 size siz=0;
 student *number;

   printf("Welcome\n\nEnter the number of student you want to evaluate: ");
   scanf("%d",&siz);

   printf("\n");


   number=malloc(siz*(sizeof(struct student)));


   for(i=0;i<siz;i++){

                      printf("Student name: ");
                      scanf("%s",number[i].name);

                      printf("Student age: ");
                      scanf("%d",&number[i].age);
                      printf("\n");
    }

      printf("Do you want to add Students(Yes or No)? ");

      void * answer;
      scanf("%s",*answer);
      
   if(strcmp(answer, "Yes")==0){

        printf("\n Give the number of the additional students: ");

        int adsize;

        scanf("%d",&adsize);

  student*realloc=(number,adsize*sizeof(int));
  int j=0;
  for(j=0;j<adsize;j++){
                           printf("Student name: ");
                           scanf("%c",number[j].name);

                           printf("Student age: ");
                           scanf("%d",number[j].age);
                           printf("\n");
  }
}
else
    printf("\nEnd of programm");





return 0;

}
1

There are 1 best solutions below

0
chqrlie On

You must learn to indent the code properly for you and others to gain readability.

Here is a reformatted version of your code:

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

typedef struct student {
    char name[30];
    int age;
} student;

int main() {
    typedef int size;
    int i;
    size siz = 0;
    student *number;

    printf("Welcome\n\nEnter the number of student you want to evaluate: ");
    scanf("%d", &siz);

    printf("\n");

    number = malloc(siz * (sizeof(struct student)));

    for (i = 0; i < siz; i++) {
        printf("Student name: ");
        scanf("%s", number[i].name);

        printf("Student age: ");
        scanf("%d", &number[i].age);
        printf("\n");
    }

    printf("Do you want to add Students(Yes or No)? ");

    void *answer;
    scanf("%s", *answer);

    if (strcmp(answer, "Yes") == 0) {

        printf("\n Give the number of the additional students: ");

        int adsize;
        scanf("%d", &adsize);

        student *realloc = (number, adsize * sizeof(int));
        int j = 0;
        for (j = 0; j < adsize; j++) {
            printf("Student name: ");
            scanf("%c", number[j].name);

            printf("Student age: ");
            scanf("%d", number[j].age);
            printf("\n");
        }
    } else
        printf("\nEnd of programm");

    return 0;
}

Some problems appear immediately:

  • typedef int size; defines a type with a local scope in the function main. Avoid this type of definition that is confusing and error prone.

  • in scanf("%d", &siz), you do not test the return value of scanf(). This is risky as invalid or missing input will be ignored and cause unexpected behavior if not undefined behavior later in the code. Always test for and report invalid or missing input:

      if (scanf("%d", &siz) != 1) {
          fprintf(stderr, "invalid or missing input\n");
          exit(1);
      }
    
  • you allocate memory with malloc but do not check for allocation failure. testing for and reporting memory allocation failure will help track problems too.

  • scanf("%s", number[i].name); does not need the & because number[i].name is an array and arrays are always passed as a pointer to their first element. Yet this scanf() call is risky because you do not provide scanf() with a way to prevent buffer overflow on overlong input. Use this instead:

      if (scanf("%29s", number[i].name) != 1) {
          fprintf(stderr, "invalid or missing input for number[%d].name\n", i);
          exit(1);
      }
    
  • scanf("%d", &number[i].age); needs the & because number[i].age is an int member and you must pass its address to scanf for it to store the converted value. Of course you must test the return value to detect and report invalid or missing input.

  • void *answer; scanf("%s", *answer); is completely bogus: you dereference a void pointer, which would not compile in Standard C (your compiler might support it an extension) and answer is uninitialized anyway, so dereferencing the pointer has undefined behavior, probably a segmentation fault, which causes your program to stop as observed. You should write this instead:

      char answer[10];
      if (scanf("%9s", answer) != 1 || strcmp(answer, "Yes")) {
          printf("end of program\n");
          return 0;
      }
    
  • student*realloc=(number,adsize*sizeof(int)); is the most surprising! it is actually parsed as

      student *realloc = (number, adsize * sizeof(int));
    

    which defines a local variable realloc as a pointer to student, initialized with the conversion of adsize * sizeof(int) as a pointer... quite meaningless and no side effect on the array pointed to by number.

  • in the second loop, scanf("%c", number[j].name) uses the wrong conversion specifier %c which reads a single character into a char variable, not a string into an array of char. Only the first character will be read (most likely a pending newline) and stored into the first entry of the name array, leaving the rest uninitialized, ie: not even forming a proper string. Use scanf("%29s", number[j].name) instead and check the return value.

You should definitely compile with extra warnings to detect such errors using gcc -Wall -Wextra -Werror or similar options for your compiler.

Here is a modified version for you to study:

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

typedef struct student {
    char name[30];
    int age;
} student;

int main(void) {
    printf("Welcome\n\n"
           "Enter the number of students you want to evaluate: ");

    int size;
    if (scanf("%d", &size) != 1 || size <= 0) {
        fprintf(stderr, "invalid or missing size\n");
        return 1;
    }

    printf("\n");

    student *number = malloc(sizeof(struct student) * size);
    if (number == NULL) {
        fprintf(stderr, "cannot allocate memory for %d students\n", size);
        return 1;
    }

    for (int i = 0; i < size; i++) {
        printf("Student name: ");
        if (scanf("%29s", number[i].name) != 1) {
            fprintf(stderr, "invalid or missing name\n");
            return 1;
        }

        printf("Student age: ");
        if (scanf("%d", &number[i].age) != 1) {
            fprintf(stderr, "invalid or missing age\n");
            return 1;
        }
        printf("\n");
    }

    printf("Do you want to add Students(Yes or No)? ");

    char answer[10];
    if (scanf("%9s", answer) == 1 && strcmp(answer, "Yes") == 0) {

        printf("\nGive the number of the additional students: ");

        int adsize;
        if (scanf("%d", &adsize) != 1 || adsize <= 0) {
            fprintf(stderr, "invalid or missing size\n");
            return 1;
        }

        student *new_number = realloc(number, sizeof(student) * (size + adsize));
        if (new_number == NULL) {
            fprintf(stderr, "cannot reallocate memory for %d extra students\n", adsize);
            return 1;
        }
        number = new_number;
        for (int i = size; i < size + adsize; i++) {
            printf("Student name: ");
            if (scanf("%29s", number[i].name) != 1) {
                fprintf(stderr, "invalid or missing name\n");
                return 1;
            }

            printf("Student age: ");
            if (scanf("%d", &number[i].age) != 1) {
                fprintf(stderr, "invalid or missing age\n");
                return 1;
            }
            printf("\n");
        }
        size += adsize;
    }
    printf("Students:\n");
    for (int i = 0; i < size; i++) {
        printf("    %s, %d\n", number[i].name, number[i].age);
    }
    printf("\n");
    printf("End of program\n");

    free(number);
    return 0;
}