0

I created a struct, it's elements are all char*. When it comes to asking inputs for these char*, i don't want to use GetString(), instead i tried scanf(). The output is definitely wrong.

Here is my code. Is scanf() able to perform the task? What is the appropriate way? If scanf() isn't, what other approaches other than GetString() (as i know how to use this function) can do it? I appreciate you help.

#include <cs50.h>
#include <stdio.h>

typedef struct
{
    char* name;
    char* add;
}person;


int main(void)
{
    printf("how many students are there: ");
    int n = 0;
    scanf("%i", &n);

    person student[n];

    for (int i = 0; i < n; i++)
    {
        printf("#%i student's name: ", i + 1);
        scanf("%s", &student[i].name);
        printf("#%i student's add: ", i + 1);
        scanf("%s", &student[i].add);
    }

    for (int i = 0; i < n; i++)
    {
        printf("#%i student's name: %s", i + 1, student[i].name);
        printf("#%i student's address: %s", i + 1, student[i].add);
    }

    return 0;
}

1 Answer 1

2

First in the struct definition, you are the declaring a pointer to a char (char*), so if you don't want to use GetString(), when you try to store something that is not a pointer on any of this elements most probably you will get a segmentation fault.

To fix this an option is to declare the char* like this:

 typedef struct
    {
        char name[255];
        char add[255];
    }person;

Notice that the 255 is arbitrary, and specifies the maximum number of chars that the element will contain. One other option, conserving your definition, could be to allocate memory once the structs are declared inside main, before you try to store the strings, like this:

for (int i = 0; i < n; i++)
{
    student[i].name = malloc(255 * sizeof(char));
    student[i].add = malloc(255 * sizeof(char));
}

Again the 255 represents the maximum number of chars that the element will contain. With this option you will need to free this memory at the end.

To actually getting the input, scanf() is an option, but scanf expects an address to store the data obtained, and student[i].name is already the address, so you don't need the &:

for (int i = 0; i < n; i++)
    {
        printf("#%i student's name: ", i + 1);
        scanf("%s", student[i].name);
        printf("#%i student's add: ", i + 1);
        scanf("%s", student[i].add);
    }

But using scanf() what if the input is longer than 255, you have a problem. So another useful function in this case can be fgets():

for (int i = 0; i < n; i++)
    {
        printf("#%i student's name: ", i + 1);
        fgets(student[i].name, sizeof(student[i].name), stdin);
        printf("#%i student's add: ", i + 1);
        fgets(student[i].add, sizeof(student[i].add), stdin);
    }

fgets() takes three arguments(the place to store the data, the maximum size to read, and where to read it from). But has also a problem, and it is that it will also store the new line character '\n'. So in this case it will read the '\n' leaved by scanf() when reads the number of students, and it will also store it at the end of every line when you introduce the name and the adress.

To consume the first new line a look at this question on StackOverflow it will help you, and to remove the trailing new line the same with this other question.

EDIT: Here is a possible solution to your program including input handling, maybe is not the best way to do it but can give you an idea:

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

#define MAX_LENGTH 255

typedef struct
{
    char name[MAX_LENGTH];
    char add[MAX_LENGTH];
}person;


int main(void)
{
    int n = 0;
    char newline, consume;

    // Get number of students
    while (true)
    {
        // Ask until a positive integer is entered
        do {
            printf("how many students are there: ");
            scanf("%i%c", &n, &newline);
        } while (n <= 0);

        // Handle invalid input, expected integer followed by a \n
        if (newline == '\n')
        {
            break;
        }

        // If the input is not the expected consume remaining elements in stdin
        do {
            scanf("%c", &consume);
        } while (consume != '\n');
    }

    // Array of persons
    person student[n];

    // Get name and adress of students using fgets()
    for (int i = 0; i < n; i++)
    {
        printf("#%i student's name: ", i + 1);
        fgets(student[i].name, sizeof(student[i].name), stdin);
        printf("#%i student's add: ", i + 1);
        fgets(student[i].add, sizeof(student[i].add), stdin);
    }

    // Clean trailing new line character from name and adress
    for (int i = 0; i < n; i++)
    {
        student[i].name[strcspn(student[i].name, "\n")] = '\0';
        student[i].add[strcspn(student[i].add, "\n")] = '\0';
    }

    // Print name and adress for every pesron
    for (int i = 0; i < n; i++)
    {
        printf("#%i student's name: %s\n", i + 1, student[i].name);
        printf("#%i student's address: %s\n", i + 1, student[i].add);
    }

    return 0;
}
5
  • you have fixed my problem, thank you.
    – hutmanew
    Commented May 26, 2015 at 2:56
  • but according to the fgets() function, can i just use if-else or do-while to verify user's input? and when i use scanf() to make input like "A B C" instead of "ABC" to the question "#1 student's name:", it doesn't store "A B C" but instead stored "A", "B" and "C" are automatically store to the answer of following next questions. how to fix that?
    – hutmanew
    Commented May 26, 2015 at 3:02
  • In C getting input can be very tedious, you always need to do error handling, About the "A B C" thing is hard to tell without seeing the code but if you do it correctly it shouldn't. I am going to update the answer with a possible solution to your program as an example.
    – wallek876
    Commented May 26, 2015 at 11:28
  • @hutmanew forgot the mention
    – wallek876
    Commented May 26, 2015 at 11:37
  • The updated answer fixes the "A B C" problem in my code. I found fgets() and the array type of char is more exact and less problematic. Thanks a lot!
    – hutmanew
    Commented May 30, 2015 at 7:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .