0

I'm currently in the process of programming the largest C program I have ever written, for a final assignment for one of my university modules. The program is modular, containing files such as main.c, librarian.c, students.c, and books.c. Each has their corresponding header file and I also have a file, structs.h, containing two structures: one for books and one for students.

I'm currently facing a problem, where when the librarian tries to add a new student membership to the library, certain inputs are completely skipped over and I don't understand why.

I'll try and include as little code as possible but this may be a challenge due to the size of my program.

First, here's my student structure as it may be relevant:

struct STUDENT             //Structure variable for student
{
  int id;
  char *name[20];
  char *pass[20];
  int mobile;
  float fee;
  int age;
  char *cat;
};
struct STUDENT student;

Now, the function that is causing me problems is this:

int student_data(int answer){ //Function to add data of student to LIS
    student_confirm();
    int x = 15, x1 = 30;
    int student_ID;
    gotoxy(x,7);printf("Enter the Information Bellow");
    gotoxy(x,10);printf("Student Name:");  gotoxy(x1,10);scanf(" %d",&student_ID);

    if(student.id==student_ID){
        gotoxy(x,11);printf("Id is already Exits");
        getch(); add_student();
    }

    student.id=student_ID;
    gotoxy(x,11);printf("User Name:");gotoxy(x1,11);scanf("%s",&student.name);       
    gotoxy(x,12);printf("Password:");gotoxy(x1,12);scanf("%s",&student.pass);
    gotoxy(x,13);printf("Mobile:");gotoxy(x1,13);scanf("%d",&student.mobile);
    gotoxy(x,14);printf("Fee:");gotoxy(x1,14);scanf("%f",&student.fee);        
    gotoxy(x,15);printf("Age:");gotoxy(x1,15);scanf("%d",&student.age);      

    return 1;
}

The student_confirm() function simply asks the user if they are sure they want to add a new student to the library. Now, when I run the program, I sign in as the librarian, go to add a student and am greeted with this in the console

                        *****Library Information System*****
                        ***Brotherton Library***
                                *1975*
                ____________________________________________
    Confirm you would like to add a new student: (Y/N)

           Enter the Information Bellow


           Student Name:
           User Name:
           Password:

It skips straight to Password, not allowing me to enter the prior two fields. I'm completely stumped by this. There's similar parts of code in my program (such as for adding books) that follow the same logic and they work just fine. I wasn't able to find anything via a search on here either.

Now, I've only been programming in C for about 6 months so I'm definitely a beginner. I'm becoming somewhat proficient but there's so much more to learn, and so much that I don't know about regarding the language.

Warnings I'm getting are:

    warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char * (*)[20]' [-Wformat=]|

for both the fields that are skipped. Is this because arrays are technically pointers? I tried changing a few things around, but like I said my books struct uses exactly the same logic as the students one, and I have an add_books function which is more or less the same as the students one provided which works without any hiccups.

Any help would be greatly appreciated and hopefully this question can help others in the future. Thanks guys and gals.

edited to add the student_confirm() function:

int student_confirm(){ //Function to confirm adding of student
  int x = 10;
  char answer;
  system("cls");window();
  printf("\n\n\n");
  gotoxy(x,5);printf("Confirm you would like to add a new student: (Y/N)");
  if(getch() == 'y' || answer == 'Y')
  student_data(answer);

 return 1;

}

  • 1
    Why is it declared `char *name[20]`? That's an array of 20 pointers to `char`. Does a student really need 20 different names? – Barmar May 02 '18 at 21:11
  • It should just be `char name[20]` to declare a single string that's up to 20 characters long. – Barmar May 02 '18 at 21:11
  • And the same for `pass`. – Barmar May 02 '18 at 21:11
  • You need to research how to handle the carriage return in the input. This question has been asked and answered many times. – David Hoelzer May 02 '18 at 21:15
  • Please show the `student_confirm()` function. It may be that you ask for a Y/N response with `%c` format spec, which needs a space in front of that spec, because unlike most format sepcifiers, `%c` does not skip whitespace remaining from the previous input. – Weather Vane May 02 '18 at 21:26
  • Note: don't use an integer type for a phone number, which may have a leading `0` which will be lost. In any case a 32-bit `int` is not big enough. – Weather Vane May 02 '18 at 21:40
  • 1
    Please see [scanf() leaves the new line char in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer). – Weather Vane May 02 '18 at 21:48
  • How do you account for the `'\n'` left in `stdin` after `scanf(" %d",&student_ID);` and before `scanf("%s",&student.name);`?? – David C. Rankin May 02 '18 at 21:55
  • (**note:** the leading space is not required in `" %d"`, but could sure be of some use in `" %s"`...) – David C. Rankin May 02 '18 at 22:02
  • @WeatherVane - I'll have a look at student_confirm() tomorrow. I'm in mobile right now and don't have the code accessible to me but I think you may be into something. DavidC.Rankin, it's possible I cannot account for it. I'll look over it tomorrow – George Strawbridge May 03 '18 at 02:55
  • @WeatherVane student_confirm() function edited into the OP. – George Strawbridge May 03 '18 at 19:10
  • As others are hinting, `scanf` is tricky to use for console input. For example, if you try to read an integer field, the newline typed to end the integer won't be removed from the input buffer. A following `scanf` to read a string will see it and immediately return an empty string. With enough care, you can convince `scanf` to behave, but it might be simper in the long run to use `fgets` or write your own string input procedure and convert the resulting strings to other types as needed. – Gene May 03 '18 at 19:16
  • @Gene could you possibly give me an example of how a problem line of my code could do the same thing with the 'fgets' function. I've only used that function for save files so would have no clue where to start. – George Strawbridge May 04 '18 at 10:53
  • Well, a hacky approach that might help is to change the string-reading scanfs by adding a space before the %s format specifier: `scanf(" %s", ...);`; This causes `scanf` to skip any whitespace it sees before starting to read the string. That ought to cause it to skip buffered newlines. When all else fails, read the documentation: **Whitespace Character** paragraph here: http://www.cplusplus.com/reference/cstdio/scanf/ – Gene May 04 '18 at 15:56

1 Answers1

1

The compiler is explaining it to you

warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char * (*)[20]'

char *name[20];

is an array of pointers to char, instead, you want an array of char's:

char name[20];

or a pointer to char:

char *name;

...
student.name = malloc(20);

and then

scanf("%s", student.name); 

Notice that you don't need to use the address of operator (&) with scanf("%s", student.name) because student.name is already (or decays into) a pointer.

Same for pass.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • Thanks for the reply. I feel kinda stupid now. I totally missed over that I'd declared them both as pointers in the struct. I have removed the pointers and the address operator but am still stuck with the same problem (skipping over the input) – George Strawbridge May 02 '18 at 21:46
  • 1
    @GeorgeStrawbridge please see my commment above, posted 20 minutes ago. – Weather Vane May 02 '18 at 21:47
  • Yes, I knew about this for programs I've written in the past. It completely skipped my mind. But adding the leading whitespace to name and pass makes the program skip even more, right down to the age line. – George Strawbridge May 02 '18 at 22:32
  • @WeatherVane please see my above post – George Strawbridge May 03 '18 at 02:52
  • @KeineLust I have done everything mentioned/advised in this thread and if anything the problem has worsened. It's skipping over more user input now. I'll post my student_confirm() function tomorrow. It might be the underlying problem. – George Strawbridge May 03 '18 at 03:00