1

I'm having a bit of a bizarre issue with C.

I have a .c file implementing a structure, and another using it. The structure in question is basic info about a student (name and grade). The Implementation file has the functions

  • initialize
  • read name
  • read grade
  • free memory (delete instance)

the main file goes as follows:

int main (void){ char inBuff[30]; char* name = NULL; int grade; Student Stu; printf("main: Please enter the name\n"); fgets(inBuff, 30, stdin); name = malloc((sizeof(char)+1)*strlen(inBuff)); strncpy (name, inBuff, 20); printf("main: Please enter the grade\n"); scanf("%d", &grade); InitializeStudent (name, grade, &Stu); /*value testing*/ printf("main: %s\n", Stu.name); printf("main: %d\n", Stu.grade); printf ("main: The student's name is %s\n", NameOfStudent(Stu)); printf ("main: The student's grade is %d\n", GradeOfStudent(Stu)); FreeStudent(&Stu); free (name); return 0; } 

printf() statements in the InitializeStudent() function seem to show the values being assigned correctly. However, both Stu.name and NameOfStudent(Stu) return ASCII, and Stu.Grade and GradeOfStudent(Stu) return 2675716 (which seems to be a memory address) regardless of input.

Of note is the fact that it has been specified that NameOfStudent() and GradeOfStudent() be pass-by-value rather than using a pointer (ie a copy of the struct should be made and passed in to the functions) and have char* and int return types respectively, whereas InitializeStudent() is passed a pointer and is a void function.

Also possibly important, the name field of Student is initialized as

char name[20]; 

rather than

char* name; 

the Student struct definition is as follows:

#define MAXNAMESIZE 20 typedef struct { char name[MAXNAMESIZE]; int grade; } Student; 

as requested, the code for initialize student is as follows

void InitializeStudent (char *name, int grade, Student *S) { printf ("InitializeStudent: entered initialization\n"); int i = 0; S = malloc (sizeof(Student)); for (i = 0; i< strlen(name); i++) if (name[i] == '\n') name[i] = '\0'; strncpy(S->name, name, 20); S->grade = grade; printf ("InitializeStudent: %s\n", S->name); printf ("InitializeStudent: %d\n", S->grade); } 
5
  • Please consider indenting your code, and adding the declaration of struct Student. EDIT: right, I noticed the code is indented except you're using tabs. For SO it's better to convert the indentation to spaces in your editor before posting. Commented Sep 27, 2013 at 17:11
  • 2
    Also possibly important is to provide us NameOfStudent and GradeOfStudent implementations. Commented Sep 27, 2013 at 17:11
  • 3
    Please show the code for InitializeStudent (name, grade, &Stu) Commented Sep 27, 2013 at 17:13
  • The expression (sizeof(char)+1)*strlen(inBuff) allocates almost twice what you need. First thing to remember is that sizeof(char) is always 1. Knowing that, you should also know that then it's enough to only allocate strlen(...) + 1 bytes. And in this case it might not even be needed to allocate that string, hard to tell until you show the InitializeStudent function. Commented Sep 27, 2013 at 17:13
  • 1
    @JoachimPileborg That whole malloc() call and the following strncpy() seem unnecessary to begin with, since InitializeStudent() has no choice but to copy the value of the name parameter into the struct member. Commented Sep 27, 2013 at 17:17

1 Answer 1

2

The problem is that you allocate the Student structure in the InitializeStudent function, when you pass it a pointer to an already allocated structure.

And because arguments are passed by value (i.e. copied) to functions, the pointer S is a copy, so when you assign to it you only assign to your local copy in the function. That is why the structure in the main function is not initialized, because you only initialize the structure you allocate in the InitializeStudent function, not the one you pass in.

And lastly, be careful with strncpy as if the source string is longer than the length you pass to it, then the function will not add the string terminator.


Oh and by the way, there is a simpler way of removing the newline from fgets: Just "remove" the last character:

/* If `name` is not a `NULL` pointer, and the length is larger than zero * and the last character is a newline... */ if (name != NULL && strlen(name) > 0 && name[strlen(name) - 1] == '\n') name[strlen(name) - 1] = '\0'; 
Sign up to request clarification or add additional context in comments.

5 Comments

Is the structure allocated when I first declare it? Otherwise, the only allocation is for the string "name" used in input. Also, as far as I was aware, passing a pointer to a function was C's way of imitating pass-by-reference and using the -> should allow me to initialize the original struct?
@user2824330 Yes, everything declared as a non-pointer is already allocated. It doesn't matter if it's native types (like int) or structures.
alright, removing the malloc in InitializeStudent seems to work.
Re. the "simpler way", at least the OP's version of that doesn't invoke UB when the string is empty
@JoachimPileborg Lol. I think it's more or less a given that the OP is already struggling to understand things as it is?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.