-3

When I try to run this code, all I get is a warning that gets() is too dangerous too use. And then when I run it, I get blank. I am suppose to display this:

Ollie     2.9   freshmen
John      3.2   senior  
Julie     2.2   freshmen
Joe       1.8   freshmen
Mary      3.8   senior  
Sue       3.4   junior  
Jane      2.7   senior  
Bob       2.8   senior  
Fred      3.2   freshmen
Bill      3.3   junior  

Here is my code:

Student *top = NULL; // to point top node of list
Student * temp, *temp1, *temp2; // for traversing list

// Creates the entire linked list from the file.
// Should call readNext and push
// Returns head of the linked list
Student *buildStudentList()
{
    Student *p; // will hold the data to be pushed in list
    p = readNext();
    push(&top, p);
    return top; //TODO: Change return
}

//Read a single line from standard input and return a student structure located on the heap
Student *readNext()
{
    Student *s = (Student*)malloc(sizeof(Student)); // allocating dynamic memory in heap
    printf("Please Enter Student Name, gpa, year :");
    gets(s->name);
    scanf("%f", &s->gpa);
    gets(s->year);
    s->next = NULL; // initially make next as NULL
    return s; //TODO: Change return
}

//Return a student structure stored on the heap
Student *makeStudent(char *name, float gpa, char *year)
{
    Student *s = (Student*)malloc(sizeof(Student));// allocating memory in heap
    s->name = name;
    s->gpa = gpa;
    s->year = year;
    s->next = NULL;
    return s; //TODO: Change return
}

//insert a new student node at the head of the linked list
void push(Student **list, Student *student)
{
    top = *list;
    student->next = top; // assign current top node of list to be second node of the list
    top = student; // make current node as top node of the list
    printf("push successful.\n");
}

//Insert a student node in the desired position on the linked list
void insert(Student *list, Student *s, int position)
{
    int i;
    top = list;
    temp = top;// temp is for traversing the list
    for (i = 1; i < position - 1; i++) // loop to reach desired position in the list
    {
        temp = temp->next;
    }
    if (temp == NULL)
    {
        printf("Position does not exist.\n");
    }
    else
    {
        s->next = temp->next;
        temp->next = s;
    }
}

//Displays contents of a single student structure
void display(Student *s) {
    printf("NAME:%s\t| GPA:%f\t| YEAR:%s\n", s->name, s->gpa, s->year);
}

//Displays contents of the entire linked list
void displayAll(Student *list)
{
    temp = list;
    while (temp != NULL)
    {
        display(temp);
        temp = temp->next;
    }
}

//Delete all data allocated on the heap before terminating program
void cleanUp(Student *list)
{
    temp1 = list; // will point to the top node of list
    temp2 = temp1->next; // will point to the second node of the list
    while (temp1 != NULL)
    {
        free(temp1);
        temp1 = temp2;
        temp2 = temp2->next;
    }
    printf("Cleanup Successful.\n");
}

//Main function tests your functions.
int main()
{
    Student *list, *s;
    printf("Program Started ");

    //Construct Linked List from Standard Input
    list = buildStudentList();

    //Insert a new student in desired position
    s = makeStudent("Max", 3.0, "senior");
    insert(list, s, 1);

    //Display entire linked list
    displayAll(list);

    //Free all heap memory
    cleanUp(list);
    printf("Program Successful Exit ");

    return 0;
    //exit(EXIT_SUCCESS);
}

And here is the output I am getting:

Program Started
Segmentation fault

Should I try to use the fgets() instead of gets()? The output I am trying to do is part of a different file, does that have a affect to it?

paddy
  • 60,864
  • 6
  • 61
  • 103
  • 3
    This code is indeed dangerous. You are reading a string into an uninitialized pointer. `fgets` will not help you with that problem. – paddy Dec 10 '18 at 05:52
  • 2
    You should never use `gets`, period. But your problem is elsewhere. – DYZ Dec 10 '18 at 05:52
  • @paddy mind telling me what the real problem is – A.Adams Dec 10 '18 at 05:54
  • @DYZ can you help explain the real problem – A.Adams Dec 10 '18 at 05:54
  • 4
    You were advised in the first comment that you have uninitialized pointers. That's the real problem. – DYZ Dec 10 '18 at 05:55
  • 1
    Please don't use a newline every other line. And indent your code. – klutt Dec 10 '18 at 05:56
  • I removed the excessive whitespace and ran the code through an auto-format to make it more readable. – paddy Dec 10 '18 at 05:57
  • @paddy Where is the uninitialized pointer? In `gets(s->name)` `s` was initialized using `malloc()`. If `name` is an array, it doesn'tneed to be initialized separately. – Barmar Dec 10 '18 at 05:59
  • 2
    Can you show the declaration of the `Student` structure? How are `name` and `year` defined? – Barmar Dec 10 '18 at 06:00
  • 1
    @barmar despite the missing definition of `Student`, I had determined the usage of the `name` member in `makeStudent` indicates it is indeed a pointer and not an array. – paddy Dec 10 '18 at 06:02
  • 1
    Read [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Basile Starynkevitch Dec 10 '18 at 06:06
  • 1
    `Student` missing. Post a [MCVE] – chux - Reinstate Monica Dec 10 '18 at 06:12
  • @paddy where is it? – A.Adams Dec 10 '18 at 06:49
  • Note that the sequence `gets(s->name); scanf("%f", &s->gpa); gets(s->year);` will only read the year if it is on the same line as the GPA. `scanf()` leaves the newline in the input buffer, and `gets()` will read it as the end of line. Don't interleave line-reading code with `scanf()` code. – Jonathan Leffler Dec 10 '18 at 06:58
  • @A.Adams where is what? – paddy Dec 10 '18 at 07:59
  • What's the purpose of `top = *list;` in your push function? If you call the function with `&top` this is useless. If you call it with any other value, you lost `top` before you assign it to `student->next`. – Gerhardh Dec 10 '18 at 09:15
  • @paddy you said there was an unintialized pointer, where is it i and some others dont see it – A.Adams Dec 10 '18 at 15:30
  • @A.Adams you've been repeatedly asked to show the definition of `struct Student`. I assume that `s->name` and `s->year` are pointers because you assign them pointer values elsewhere in the code and that would not compile if they were arrays. The fact is, if these _are_ pointers then yes, like I said in the very first comment, they are uninitialized. Initialization means giving something a value. For pointers, you need to point them at memory owned by your process. – paddy Dec 10 '18 at 21:36

2 Answers2

3

Ignoring warnings is never the right thing to do. The aim is not just to remove the warnings using some hack but to address the root cause that produces warning. In this particular case, the compiler explicitly has warned you that using gets is too dangerous. Why would you not heed such a clear warning?

gets has been removed from the standard from C11 onwards.

The gets() function does not perform bounds checking, therefore this function is extremely vulnerable to buffer-overflow attacks. It cannot be used safely (unless the program runs in an environment which restricts what can appear on stdin). For this reason, the function has been deprecated in the third corrigendum to the C99 standard and removed altogether in the C11 standard. fgets() and gets_s() are the recommended replacements.

Never use gets().

Also look at your memory allocation/deallocation for the members of the struct.

Also read this question on whether the result of malloc should be cast.

Community
  • 1
  • 1
P.W
  • 26,289
  • 6
  • 39
  • 76
0

Hello I went through your code, assuming that your structure description is as follows:

typedef struct Student_s{
    char name[32];
    float gpa;
    char year[5];
    struct Student_s* next;
}Student;

The problem with gets() is already pointed out in previous answer by P.W . You could use scanf("%s",s->name) instead of gets(),

And in makeStudent() you should be using strcpy() for copying string. [ Reason ]

Also in cleanUp() consider the case when the last node is being freed, temp1 will be pointing to the last node and temp2 to NULL. In this situation if you do a temp2 = temp2->next it will result in segmentation fault. You could avoid that by enclosing the statement in an if.

if(temp2 != NULL){
    temp2 = temp2->next;
}
PunyCode
  • 373
  • 4
  • 18