【发布时间】: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(&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。所以也许我实际上应该将&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 = &p; 有效,尽管p 本身是一个指针,所以s 应该是指向void 的指针,所以void** s 而不是void* s。
同样memset函数返回一个指向内存区域s的指针,所以如果s = &p和p = &myStruct,那么它返回一个指向结构的内存区域的指针,所以一个指向&myStruct的指针。也许这就是它起作用的原因。
-
打印 sizeof(p) 并与 sizeof(struct car) 进行比较。
-
使用
memset(p, 0, sizeof(*p));获取结构的大小,而不是指针的大小 -
sizeof(p)是指针的大小。你想要sizeof(*p)或sizeof(struct car)如果你想memset整个指向对象