简体   繁体   English

C —结构和指针基本问题

[英]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: 因此,我现在正在尝试学习C,还有一些基本的结构性问题需要解决:

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. 我肯定在某种程度上是错误的...我也认为我的setName实现不正确。

Any pointers? 有指针吗? (no pun intended) (无双关语)

This is very wrong. 这是非常错误的。 If you insist on not using strcpy do something like this (not tested) 如果您坚持不使用strcpy请执行以下操作(未经测试)

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. 因为s对象在函数退出时被销毁-它在函数作用域中是局部的,但是您返回了指向它的指针。 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 . 如果要执行此操作,则应使用malloc动态分配它。 Alternatively do not return a pointer at all and use the alternative option of @Andrew . 或者,根本不返回指针,而使用@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. 在“另一个方法”中,您在本地声明Student s ,它将动态分配空间(通常在堆栈上),并在完成时返回该地址。

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: 在对方法的调用中声明Student s ,并将指针传递给makeAndrew:

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


...

Student s;
makeAndrew( &s );

...

Your function makeAndrew returns pointer to a local variable. 您的函数makeAndrew返回指向局部变量的指针。 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. 您将不得不动态分配它(使用Student *s = new Student;或者如果您真的想坚持使用纯C,则Student *s = malloc (sizeof Student );然后在它不是函数之后将其释放到函数外部需要避免内存泄漏。

Or do it as Andrew suggested, it's less error-prone. 或按照安德鲁(Andrew)的建议去做,它不容易出错。

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: 我将makeAndrew()函数更改为仅返回一个结构,而不是指向结构的指针以更正有关返回指向临时变量的指针的错误:

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. 您的setName确实存在关于temp的错误,应该为char *,因为您正在循环中将其递增以指向输入c字符串中的另一个字符。 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: 正如您在评论中提到的那样,应该检查Student中名称char数组是否溢出:

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: 您可以使用strncpy简化setName:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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