简体   繁体   中英

C — Structs and Pointers Basic Questions

So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:

Basically, everything centers around this snippet of code:

#include <stdio.h>
#include <stdlib.h>

#define MAX_NAME_LEN 127

typedef struct {
    char name[MAX_NAME_LEN + 1];
    unsigned long sid;
} Student;

/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
    return s->name; // returns the 'name' member of a Student struct
}

/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |     'name' is a pointer to the first element of a char array (repres. a string)
    char temp;
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
    *((s->name) + i) = temp;
}

/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
    return s->sid;
}

/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
    s->sid = sid;
}

I've commented up the code in an attempt to solidify my understanding of pointers; I hope they're all accurate.

Also, I have another method,

Student* makeAndrew(void) {
    Student s;
    setName(&s, "Andrew");
    setStudentID(&s, 12345678);
    return &s;
}

which I'm sure is wrong in some way... I also think my setName is implemented incorrectly.

Any pointers? (no pun intended)

This is very wrong. If you insist on not using strcpy do something like this (not tested)

int iStringLength = strlen(name);
for (i = 0; i < iStringLength; i++) {
    s->name[i] = name[i];
}

but make sure that the length is not longer than your array size.

This is also wrong

Student* makeAndrew(void) {
   Student s;
   setName(&s, "Andrew");
   setStudentID(&s, 12345678);
   return &s; 
}

because the s object is destroyed when the function exits - it is local to the function scope and yet you return a pointer to it. So if you try to access the struct using this pointer it will not be valid as the instance no longer exists. If you want to do this you should dynamically allocate it using malloc . Alternatively do not return a pointer at all and use the alternative option of @Andrew .

In your "another method" you are locally declaring Student s , which will dynamically allocate space (usually on the stack) and you are returning that address on completion.

However, that stack-space will be released on the return, so there is no guarantee that the data is uncorrupted - in fact the likelyhood is that it will be!

Declare Student s in the call to your method, and pass the pointer to makeAndrew:

void makeAndrew(Student *s) {
    setName( s, "Andrew");
    setStudentID( s, 12345678);
}


...

Student s;
makeAndrew( &s );

...

Your function makeAndrew returns pointer to a local variable. It is only valid before the scope ends, so as soon as the function finishes, it will change when the memory gets overwritten - ie almost instantly. You would have to allocate it dynamically (using Student *s = new Student; , or if you really want to stick to pure C, Student *s = malloc (sizeof Student ); , and then free it outside the function after it is not needed to avoid memory leak.

Or do it as Andrew suggested, it's less error-prone.

I would change the makeAndrew() function to just return a struct, not a pointer to a struct to correct the error with respect to returning a pointer to a temporary variable:

Student makeAndrew(void) 
{
    Student s;
    setName(&s, "Andrew");
    setStudentID(&s, 12345678);
    return s;
}

Student aStudent = makeAndrew();

Your setName does have an error with respect to temp, which should be a char *, since you are incrementing it in your loop to point to another character in the input c-string. I think it was missing the null termination as well. And as you mention in your comment, there should be a check for overflow of the name char array in Student:

void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |     
    // 'name' is a pointer to the first element of a char array (repres. a string)
    const char *temp;
    int i;
    for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++) 
    {
       *((s->name) + i) = *temp;
    }
    s->name[i] = '\0';
}

You can use strncpy to simplify setName:

void setName2(Student *s,const char *name)
{
    #include <string.h>
    strncpy(s->name, name,MAX_NAME_LEN);
    s->name[MAX_NAME_LEN] = '\0';
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM