0

I am trying to make a program that manages info of students. But I just can't use pointer well due to lack of my c programming skill.

Here is source code:

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

typedef struct
{
    int id;
    char fName[8];
    char lName[8];
} Student;

void main()
{

    int size = 0;
    int i = 0;

    /* get max lines */
    scanf("%d", &size);

    Student *students = (Student*) malloc(sizeof(Student) * size); // allocate whole table
    Student *pointAt = students; // pointer used to point whole table by memory address

    /* retrieves data from stdin */
    for (i = 0; i < size; i++)
    {
        scanf("%d", &((*pointAt).id));
        printf("recorded id at %d is %d\n", i, (*pointAt).id);
        fgets((*pointAt).fName, sizeof((*pointAt).fName), stdin);
        printf("recorded fName at %d is %s\n", i, (*pointAt).fName);
        fgets((*pointAt).lName, sizeof((*pointAt).lName), stdin);
        printf("recorded lName at %d is %s\n", i, (*pointAt).lName);
        while (getchar() != '\n')
            ;
    }

    free(students);
}

And the text file I read from, called test.txt, is:

2
11223344 Jennifer Smith
22334455 John Bob

*Note that here 2 on the first line is used to set the size of dynamically allocated struct, used at : Student students = (Student)malloc(sizeof(Student) * size); because there are only 2 students, Jennifer and John.

And here is command I run to test this:

a.out < test.txt

And here is output:

recorded id at 0 is 11223344
recorded fName at 0 is  Jennif
recorded lName at 0 is er Smit
recorded id at 1 is 22334455
recorded fName at 1 is  John B
recorded lName at 1 is ob
^Z
Suspended

The problems are:

  1. It seems it retrieves studentID well, but not first name(fName) and last name(lName). It seems fName retrieves space as well, which it should avoid of.

  2. Program gets into infinite loop due to use of "while (getchar() != '\n');" to clear input buffer. So I pressed ctrl+z(^Z) to force terminate program, which you can see in my sample output.

How can I fix this? Thank you very much..


Changed part of source after first fixing:

for(i=0; i<size; i++) {
scanf("%d", &((*pointAt).id));
printf("recorded id at %d is %d\n", i, (*pointAt).id);
getchar();
fgets((*pointAt).fName, sizeof((*pointAt).fName), stdin);
printf("recorded fName at %d is %s\n", i, (*pointAt).fName);
getchar();
fgets((*pointAt).lName, sizeof((*pointAt).lName), stdin);
printf("recorded lName at %d is %s\n", i, (*pointAt).lName);
}

And output after first fixing:

recorded id at 0 is 11223344
recorded fName at 0 is Jennifer
recorded lName at 0 is Smith

recorded id at 1 is 22334455
recorded fName at 1 is John Bob
recorded lName at 1 is Smith
2
  • Please indent your code. Commented Jan 26, 2017 at 15:00
  • 3
    So.. you have the counter variable i in your for loop. But you don't do anything useful with it to progress in your students list. Commented Jan 26, 2017 at 15:01

3 Answers 3

1

fgets does exactly what you asked it to. You pass and declare a buffer of eight characters. The previous read was a scanf %d so it has stopped on first non digit character, here the space. The input stream is then positioned on Jenniffer... (notice the initial space character!). fgets reads 7 characters and put a terminating null in 8th position which give:

 1 2 3 4 5 6 7 8
   J e n n i f \0

How to fix? Stop mixing fgets and scanf... and increase the size of your buffers. As the longest name is Jennifer (8 characters) the minimum size is 9 to include the terminating null. And also avoid that awful hack: while (getchar() != '\n'; which is guaranteed to lead to an infinite loop if the file is not terminated by a \n or if the last \n has been eaten by a fgets

Last but not least, control the return value of input functions like scanf. Also main is required to return an int not a void and malloc return value should never be casted in C...

Fixed code could look like:

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

typedef struct
{
    int id;
    char fName[12];    
    char lName[12];
} Student;

int main()
{

    int size = 0;
    int i = 0;

    /* get max lines */
    int cr = scanf("%d", &size);
    if (cr != 1) {
        fprintf(stderr, "Incorrect size");
        return 1;
    }

    Student *students = malloc(sizeof(Student) * size); // allocate whole table
    Student *pointAt = students; // pointer used to point whole table by memory address

    /* retrieves data from stdin */
    for (i = 0; i < size; i++)
    {
        cr = scanf("%d%11s%11s", &(pointAt->id),pointAt->fName, pointAt->lName);
        if (cr != 3) {
            fprintf(stderr, "Incorrect format line %d\n", i+1);
            return 1;
        }
        printf("recorded id at %d is %d\n", i, (*pointAt).id);
        printf("recorded fName at %d is %s\n", i, (*pointAt).fName);
        printf("recorded lName at %d is %s\n", i, (*pointAt).lName);
        pointAt += 1; // point to next struct in array
    }
    free(students);
    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

This is an actual complete answer. Thank you very much!
1

Try to fix these two problems:

  1. Increase the size of the fname (and optionally lname to keep it consistent with fname) from 8 to 9. Your first input "jennifer" is 8 character long. But fgets also counts '\0' as another character. So it thinks that "jennifer\0" is 9 character long. So increase the size of fname to 9 characters to accommodate the whole string.
  2. You have a space between the fields ID and fname and then fname and lname. You need to consume that space character. Notice an extra space in your output. You can consume it using a getchar().

11 Comments

That almost fixed my problem. Thank you.
Cool. What is it that is still not fixed?
recorded fName at 1 is John Bob
recorded lName at 1 is Smith
above are output after fixing. but first one's fName should be just just John, and second comment's lName should be Bob instead of Smith. I don't know why "John" and "Bob" are put into fName all together
|
1

You actually don't need to use one more variable 'pointAt'. You could very well do your stuff with your malloc'ed struct 'students'. Even if you do, it's a good practice to make 'pointAt' as NULL after freeing allocated struct.

free(students);
pointAt = NULL;
return 0;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.