【问题标题】:Pointers, structs and memset in C [duplicate]C中的指针,结构和memset
【发布时间】:2022-09-30 21:54:18
【问题描述】:

我已经学习 C 几天了,没有任何其他编程经验,所以在问我的问题时我可能不清楚。它主要是关于指针。为方便起见,我为变量命名,这样没人会感到困惑。

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

struct car {            
        char* name;
        int speed;
        float price;
};

void fun(struct car* p); 

int main(void) {

        struct car myStruct = { .name = \"FORD\", .speed = 55, .price = 67.87 };
        
        fun(&myStruct);

        printf(\"%d\\n\", myStruct.name == NULL);
        printf(\"%d\\n\", myStruct.speed == 0);
        printf(\"%d\\n\", myStruct.price == 0.0);

        return(0);
}


void fun(struct car* p) {
        memset(p, 0, sizeof(p));
}       

这是我的代码。

我全局声明了struct car 类型,所以它可以被其他函数看到。

我编写了一个函数原型,它接受struct car* 类型的参数并将参数的副本存储到函数本地的参数p 中。

后来,我写了实际的函数体。如您所见,我调用了 string.h 标头中的 memset 函数。根据 Linux 手册页,它看起来像这样 void* memset(void* s, int c, size_t n);

在这种情况下,memset 函数的作用是将struct car* p 指向的内存区域的第一个sizeof(struct car* p) 字节填充为常量字节c,在这种情况下为0。

main 函数中,我初始化myStruct 类型为struct car 的变量,然后调用函数fun 并将myStruct 的地址传递给函数。然后我想通过调用printf 函数来检查是否所有struct car“数据成员”都设置为0。

我得到的输出是

1
0
0

这意味着只有第一个“数据成员”设置为 NULL,其余的都没有。

另一方面,如果我在 main 函数中调用 memset 函数,我得到的输出是

1
1
1

如果我正确理解指针(距离我第一次听说它们已经有几天了,所以我的知识不是最佳的),struct car myStruct 在内存中有自己的地址,比如说1为了方便。

参数struct car* p在内存中也有自己的地址,比如说2,它存储(指向)变量struct car myStruct的地址,所以指向1地址,因为我将它传递给这里的功能fun(&amp;myStruct);

因此,通过取消引用参数p,例如(*p).name,我可以更改“数据成员”变量的值,并且将在全局范围内看到效果,因为即使p 参数只是原始的myStruct 变量,它指向与myStruct 变量相同的地址,通过取消引用指针struct car* p,我检索存储在指针指向的地址的数据。

所以(*p).name 将给我\"FORD\"(*p).name = \"TOYOTA\" 将在函数fun 中本地和在其他函数中全局更改数据,如果不创建指针变量,这是不可能的,如果我这样做p.name = \"TOYOTA\",它仅更改副本的值,该副本在内存中具有自己的地址,该地址与函数fun 中的本地“数据成员”变量名的原始结构变量的地址不同。它发生了,因为在这种情况下,我只对原始 myStruct 变量的副本进行操作,而不是对原始变量进行操作。

我认为在 C 中只有值传递,所以本质上每个参数只是原始变量的副本,但是指针使它可以传递原始变量的地址(所以它就像 \"passing通过引用\”,但无论如何都会进行复制,问题是该函数对原始地址而不是参数的地址进行操作)。

我不知道的是,为什么memset 函数只将第一个“数据成员”变量更改为 NULL 而不是全部?

void fun(struct car* p) {
        memset(p, 0, sizeof(p));
        p->name = NULL;
        p->speed = 0;
        p->price = 0.0;
}       

如果我这样做,那么它将所有值更改为NULL, 0, 0,但我不知道这样做是否是一个好习惯,因为在这种情况下没有必要,因为我明确初始化了所有“数据成员” \" 在具有某些值的结构中。

void fun(struct car* p) {
        memset(&p, 0, sizeof(p));
}

这也有效并提供NULL, 0, 0。所以也许我实际上应该将&amp;s 传递给函数而不是s,但我不知道这是如何工作的。函数void* memset(void* s, int c, size_t n); 以void* 作为参数而不是void**,后者是可以理解的,因为:

struct car myStruct = { .name = \"FORD\", .speed = 55, .price = 67.87 }; // It has its own address in memory and stores the struct at this address
struct car* p = &myStruct; // It points to the address of myStruct and retrieves the data from there when dereference happens, so first it goes to address 1 and then gets the data from this address
void** s = &p; // It points to the address of p and retrieves the data from there when double dereference happens, so it first goes to address 2 and gets the data and the data is address 1, then it goes to address 1 and gets the data, so the struct

但是void* 表示指向 void 的指针,因此指向任何数据类型。这让我很困惑为什么void* s = &amp;p; 有效,尽管p 本身是一个指针,所以s 应该是指向void 的指针,所以void** s 而不是void* s

同样memset函数返回一个指向内存区域s的指针,所以如果s = &amp;pp = &amp;myStruct,那么它返回一个指向结构的内存区域的指针,所以一个指向&amp;myStruct的指针。也许这就是它起作用的原因。

  • 打印 sizeof(p) 并与 sizeof(struct car) 进行比较。
  • 使用memset(p, 0, sizeof(*p)); 获取结构的大小,而不是指针的大小
  • sizeof(p) 是指针的大小。你想要sizeof(*p)sizeof(struct car) 如果你想memset 整个指向对象

标签: c pointers struct memset


【解决方案1】:

在这次通话中

memset(p, 0, sizeof(p));

您仅将结构中等于指针p 大小的部分设置为0。

相反,你需要写

memset(p, 0, sizeof(*p));

也就是将结构类型的整个对象设置为0。

注意因为变量 p 是一个指针然后这条记录

p.name = "TOYOTA";

只是语法不正确。

至于这个问题

void fun(struct car* p) {
        memset(p, 0, sizeof(p));
        p->name = NULL;
        p->speed = 0;
        p->price = 0.0;
}       

如果我这样做,它会将所有值更改为 NULL、0、0,但我没有 知道,如果这样做是一个好习惯,因为在这方面是不必要的 案例,因为我显式初始化了所有“数据成员” 具有一定价值的结构。

然后由于宏 NULL 具有实现定义的值(尽管在大多数情况下它被扩展为 0),因此最好显式设置指向 NULL 的指针,例如

p->name = NULL;

而不是使用 memset。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-19
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多