3

So as part of a school assignment I have to create an application to handle the input of various fields using a structure. defined outside of main as following

typedef struct stud {
    struct number {
        int studNum;
    } number;
    struct name {
        char firstName[NAME_SIZE];
        char lastName[NAME_SIZE];
    } name;
    struct cellNum {
        int areaCode;
        int prefix;
        int suffix;
    } cellNum;
    struct courses {
        struct fall {
            char className[NAME_SIZE];
            float mark;
        } fall;
        struct winter {
            char className[NAME_SIZE];
            float mark;
        } winter;
    } courses;
} stud;

NAME_SIZE is defined as 30

I access the struct as following

stud studArray[100]; // max 100 students
stud *studPtr;

for (int i = 0; i < studCount; i++) {
    studPtr = &studArray[i];
    initializeStrings(studPtr[i]);
    getNum(studPtr[i]);
    getName(studPtr[i]);
    getCell(studPtr[i]);
    getCourses(studPtr[i]);
}

initializeStrings is where I add the null terminator's

void initializeStrings(stud student) {
    student.name.firstName[NAME_SIZE - 1] = '\0'; 
    student.name.lastName[NAME_SIZE -1] = '\0';
    student.courses.fall.className[NAME_SIZE -1] = '\0';
    student.courses.winter.className[NAME_SIZE -1] = '\0';
}

This is now where the problem occurs: in any of my various functions, when I try and access any of the information I write to my string, I get an output of garbage characters that look like a sideways T, but only if i access the data in a different function.

Example: this is the code to get 2 courses and marks

void getCourses(stud student) {
    getchar();
    printf("\n%s", "Enter Course name - Fall 2016: ");
    fgets(student.courses.fall.className, NAME_SIZE - 1, stdin);
    fflush(stdin); // suggested by my prof to fix the issue, did nothing

    printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
    scanf("%f", &student.courses.fall.mark);

    getchar();
    printf("\n%s", "Enter Course name - Winter 2017: ");
    fgets(student.courses.winter.className, NAME_SIZE - 1, stdin);

    printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
    scanf("%f", &student.courses.winter.mark);
}

If I enter helloWorld as a course name, the system correctly prints enter mark received for helloWorld

but when I try and print the data from my print function:

void printData(stud student) {
// various other values (none of which work)
printf("\t%s\t%s\t%f\n", "Fall2016", student.courses.fall.className, student.courses.fall.mark);
}

I get garbage data output ( image )

Any help/code criticism welcome

EDIT: Thank you Eddiem, and everyone else, you pointed me in the right direction.

  • Where is `printData(stud)` being called? I don't see it in code snippet 2. – Dellowar Nov 30 '16 at 19:33
  • in a seperate for loop right below snippet 2 `for (int i = 0; i < studCount; i++) { printData(studPtr[i]); }` This allows 2 or more students to be entered before the final table is printed – SCREAM2NIGHT Nov 30 '16 at 19:36
  • You are passing a `struct` to `initializeStrings` and other `struct` members to functions which do not find their way back, because you only pass a copy. You could initialise your structs with `stud studArray[100] = {0};` – Weather Vane Nov 30 '16 at 19:41
  • 2
    `fflush(stdin);` invokes undefined behavior – chqrlie Nov 30 '16 at 19:44
  • Well laid out question. Keep it up. – Dellowar Nov 30 '16 at 20:01

3 Answers3

1

This code doesn't really make sense. First, why not pass stud* pointers to each of the functions you're calling below? Regardless, the way you have it here, you're initializing studPtr to point to a particular element in the studArray array, but then still indexing i into that pointer. You could probably pass studPtr[0], but that's just weird.

Original code:

stud studArray[100]; // max 100 students
stud *studPtr;

for (int i = 0; i < studCount; i++) {
    studPtr = &studArray[i];
    initializeStrings(studPtr[i]);
    getNum(studPtr[i]);
    getName(studPtr[i]);
    getCell(studPtr[i]);
    getCourses(studPtr[i]);
}

I would suggest modifications like the following:

void initializeStrings(stud *student) {
    student->name.firstName[NAME_SIZE - 1] = '\0'; 
    student->name.lastName[NAME_SIZE -1] = '\0';
    student->courses.fall.className[NAME_SIZE -1] = '\0';
    student->courses.winter.className[NAME_SIZE -1] = '\0';
}

These modifications would need to be made to each if the functions that currently take a stud parameter. Then, change your loop initialization to:

for (int i = 0; i < studCount; i++) {
    initializeStrings(&studArray[i]);
    getNum(&studArray[i]);
    getName(&studArray[i]);
    getCell(&studArray[i]);
    getCourses(&studArray[i]);
}
eddiem
  • 1,030
  • 6
  • 9
0

This is not right:

studPtr = &studArray[i];
initializeStrings(studPtr[i]);

Say you want to access the third element of your array, so i is 3. This gives you an offset to that third entry:

studPtr = &studArray[i];

Now you use an index with that....

initializeStrings(studPtr[i]);

So you're accessing 3 elements further than the third one you're already at; i.e. element 6. You can see you're going to step off the end of the array, or access elements you haven't initialised.

So use either:

studPtr = &studArray[i];
initializeStrings(studPtr);

or

initializeStrings(&studArray[i]);

Those two amount to the same thing, and point at the same place.

gilez
  • 669
  • 3
  • 6
0

The problem is you're not passing by reference (aka using pointers). If you don't use pointers then functions like getCourses modify temporary data instead of the data directly. Thus, the junk values in the original data are never removed.

Change

void getCourses(stud student) { // no pointer = copy data to temporary memory, original data is unmodified in this function.
getchar();
printf("\n%s", "Enter Course name - Fall 2016: ");
fgets(student.courses.fall.className, NAME_SIZE - 1, stdin);
fflush(stdin); // suggested by my prof to fix the issue, did nothing

printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
scanf("%f", &student.courses.fall.mark);

getchar();
printf("\n%s", "Enter Course name - Winter 2017: ");
fgets(student.courses.winter.className, NAME_SIZE - 1, stdin);

printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
scanf("%f", &student.courses.winter.mark);
}

To

void getCourses(stud *student) { // notice the pointer used. Original data is to be modified.
getchar();
printf("\n%s", "Enter Course name - Fall 2016: ");
fgets(student->courses.fall.className, NAME_SIZE - 1, stdin);
fflush(stdin); // suggested by my prof to fix the issue, did nothing

printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
scanf("%f", &student->courses.fall.mark);

getchar();
printf("\n%s", "Enter Course name - Winter 2017: ");
fgets(student->courses.winter.className, NAME_SIZE - 1, stdin);

printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
scanf("%f", &student->courses.winter.mark);
}

Further more, you must modify your for loop to handle the pointers. Ie, change getCourses(studPtr[i]); to getCourses(&studPtr[i]);

Dellowar
  • 3,160
  • 1
  • 18
  • 37