-2

I'm creating a simple program using the C programming language. Unfortunately, I'm having a problem with a piece of source code right now. I am not able to store data in the students structure after running the program.

I think the problem is the gets() function in the ADD_Students() function. (Line 60)

Here is my source code: (Used code blocks with gnu gcc compiler in windows 10)

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

#define TRUE 1
#define MAX 3

struct Students
{
    char * Name;
    char * Field;
    char * City;

    unsigned int Student_ID;
    float Mark;
}Addr_INFO[MAX];


char Menu();
void ADD_Students();
void DEL_Students();
void EDT_Students();

int main()
{
    char Selected_ITEM;

    while (TRUE)
    {
        Selected_ITEM = Menu();

        switch (Selected_ITEM)
        {
            case '1' : ADD_Students(); break;
            case '2' : DEL_Students(); break;
            case '3' : EDT_Students(); break;
            default : printf("Wrong number!\n"); exit(0);
        }
    }
}


char Menu()
{
    char Chose;

    printf(".----------+ Students information management +----------.\n\n");
    printf("[1]. ADD student\n");
    printf("[2]. DEL student\n");
    printf("[3]. EDT student\n\n");

    printf("Please enter your choice: ");
    scanf("%c", &Chose);

    return Chose;
}


void ADD_Students()
{
    register int i;

    for (i = 0; i < MAX; i++)
    {
        printf("[S-%d]. Name: ", i);
        gets(Addr_INFO[i].Name);
        printf("[S-%d]. Field: ", i);
        gets(Addr_INFO[i].Field);
        printf("[S-%d]. City: ", i);
        gets(Addr_INFO[i].City);
        printf("[S-%d]. ID: ", i);
        scanf("%d", &Addr_INFO[i].Student_ID);
        printf("[S-%d]. Mark: ", i);
        scanf("%.2f", &Addr_INFO[i].Mark);
        printf("\n");
    }
}


void DEL_Students()
{
    printf("Test2");
}


void EDT_Students()
{
    printf("Test3");
}

what's going on?

Why this is happened?

Ouput

.----------+ Students information management +----------.

[1]. ADD student
[2]. DEL student
[3]. EDT student

Please enter your choice: 1
[S-0]. Name: [S-0]. Field: [S-0]. City: [S-0]. ID:
D.H
  • 37
  • 1
  • 7
  • Please explain the nature of the problem; if you get an error message, what does it say? If it produces the wrong result, what is it an what should it be? When you run it with a debugger, what is the *first* thing the program does incorrectly? – Scott Hunter Feb 11 '20 at 15:32
  • 8
    The `scanf()` call leaves the newline in the input buffer. Therefore, `gets()` reads up to the first newline. And you should NOT be using `gets()` ever! Never, never, never, *never*, **never**, ***NEVER*** use `gets()`! – Jonathan Leffler Feb 11 '20 at 15:36
  • @JonathanLeffler -- Is there [a problem with the `gets()` function](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used)? ;) – ad absurdum Feb 11 '20 at 15:42
  • 1
    It is deprecated - also suffers from buffer overflows – Ed Heal Feb 11 '20 at 15:43
  • Jonathan Leffler , So what function should I use to get the string? – D.H Feb 11 '20 at 15:45
  • 2
    Use `fgets()`, but you’ll still need to deal with the newline left over from `scanf()` and `%c`. And the newline included in the input by `fgets()`. The Q&A linked to by ex nihilo explains the problemcc GCC and the alternatives. – Jonathan Leffler Feb 11 '20 at 15:47
  • You should be able to reduce this to a [mcve] of your problem, without all the extraneous parts (`struct Students` etc.). – Toby Speight Feb 11 '20 at 20:38
  • Not the cause of your problem, but it's a good idea to make all your function declarations *prototypes* - i.e. specify what arguments they take; `(void)` if no arguments. – Toby Speight Feb 11 '20 at 20:39

2 Answers2

1

There is a problem in your code. You are passing an uninitialized pointer to gets.

You never add an actual bit of memory to your Addr_INFO entries. You should either declare the members as an array of some appropriate size or gets the data into a local buffer and then allocate memory (malloc) of sufficient size and copy the local data to that buffer and assign its pointer you to the member.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
1

First problem - NEVER NEVER NEVER NEVER NEVER NEVER use gets. It has been removed from the standard library as of the 2011 standard, and it will (not might, will) introduce a point of failure in your program. It is the programming equivalent of plutonium. Use fgets instead:

if ( fgets(Addr_INFO[i].Name, MAX_NAME_LEN, stdin) == NULL )
  // error on input
else
  // process Addr_INFO[i].Name

Second problem - you never set aside any memory to actually store a name, field, or city. All you've done is declare the pointers, but you never set them to point anywhere meaningful. They initially contain some random bit pattern that very likely doesn't correspond to a valid address.

For a simple program like this, it's probably better to declare those fields as arrays of char, rather than just pointers:

#define MAX_NAME_LEN  40 // or whatever you expect the longest name to be
#define MAX_FIELD_LEN 40 // same as above
#define MAX_CITY_LEN  40 // same as above 

struct Students
{
    char Name[MAX_NAME_LEN + 1];  // +1 for string terminator
    char Field[MAX_FIELD_LEN + 1];
    char City[MAX_CITY_LEN + 1];

    unsigned int Student_ID;
    float Mark;
}Addr_INFO[MAX];

And then your fgets call changes ever-so-slightly to

if ( fgets( AddrInfo[i].Name, sizeof AddrInfo[i].Name, stdin ) == NULL )
  // error on input
else
  // process AddrInfo[i].Name
John Bode
  • 119,563
  • 19
  • 122
  • 198