结构中指针表示法和点表示法之间的混淆[重复]
Posted
技术标签:
【中文标题】结构中指针表示法和点表示法之间的混淆[重复]【英文标题】:Confusion between Pointer Notation and Dot Notation in Structs [duplicate] 【发布时间】:2021-12-19 07:56:11 【问题描述】:我正在尝试将 Struct 中的所有名称设为小写,以便我可以比较它们并删除它们。
int removeNameCard(NameCard *idCard, int *size)
char name[80];
char *ptr;
char rubbish;
int a = 0, c = 0;
printf("removeNameCard():\n");
printf("Enter personName:\n");
scanf("%c", &rubbish); // Why is there a '\n' char here??
fgets(name, 80, stdin);
if((ptr = strchr(name, '\n')))
*ptr = '\0';
if((*size) == 0)
printf("The name card holder is empty\n");
return 0;
// Convert everything to Lower Case first
while(name[a])
name[a] = tolower(name[a]);
a += 1;
printf("tolower(): %s", name);
for(int b = 0; b < *size; b += 1)
// Why is this Dot Notation when I passed in a pointer to the Struct?
while (idCard[b].personName)[c])
(idCard[b].personName)[c] = tolower((idCard[b].personName)[c]);
c += 1;
for(int i = 0; i < *size; i += 1)
if((idCard[i].personName) == name)
printf("%d. This is from Holder: %s, This is from User: %s", i,(idCard[i].personName),name);
printf("The name card is removed\n");
printf("nameCardID: %d\n", idCard[i].nameCardID);
printf("personName: %s\n", idCard[i].personName);
printf("companyName: %s\n", idCard[i].companyName);
int k = 0;
do
idCard[i+k].nameCardID = idCard[i+k+1].nameCardID;
strcpy((idCard[i+k].personName),(idCard[i+k+1].personName));
strcpy((idCard[i+k].companyName),(idCard[i+k+1].companyName));
while((i+k+1) != (*size + 1));
return 0;
但是,我很困惑为什么编译器要求我使用点表示法而不是指针表示法,因为我认为我将 Struct 的地址传递到 *idCard 所以如果我没记错的话它应该是一个指针?
我尝试像这样访问 Struct 的每个名称中的每个单独的字符是不是错了? (身份证[b].personName)[c]
谢谢
【问题讨论】:
我不禁想到你的minimal reproducible example 可能会更小。 如果idCard
是NameCard
结构的数组,那么idCard[b]
就是这样一个NameCard
结构object。 idCard[b]
不是指向结构的指针(将使用“箭头”运算符 ->
)。这就是为什么在idCard[b].personName
中应该使用“点”运算符.
。
另外,(idCard[b].personName)[c]
不需要括号,idCard[b].personName[c]
也可以。
顺便说一句:if((idCard[i].personName) == name)
不是比较字符串的方法,
@Antoine 是的,它极大地帮助了我理解这两个运算符存在的原因,尽管我可能需要编写更多代码才能完全理解评论的完整解释。非常感谢,我学到了很多:>
【参考方案1】:
但是,我很困惑为什么编译器要求我使用点表示法而不是指针表示法,因为我认为我将 Struct 的地址传递到 *idCard 所以如果我没记错的话它应该是一个指针?
数组大多只是指向数组中第一个元素的指针(编译器可能知道数组大小除外)。
因为数组大多只是指针;对于整数数组myInt = myIntArray[x];
就像myInt = *(myIntArray + x);
- 指针取消引用由数组索引暗示。请注意,要访问数组中int
中间的char
,您可以(不可移植地)使用myChar = *((char *)(myIntArray + x)) + offset_of_char_in_int);
之类的东西;这有点像访问结构数组中的字段(因为它们都在访问较大事物数组中的较小事物)。
对于结构数组;索引数组会导致取消引用(就像它对整数数组所做的那样);所以myIDcardStruct = idCard[i];
就像myIDcardStruct = *(idcard + i);
。因为数组索引隐含了取消引用,myIDcardStruct
不是指针。
->
运算符就像将请求结构的字段的偏移量添加到地址,将地址转换为请求字段的类型,然后取消引用。换句话说,myInt = myStructPointer->myIntField;
就像 myInt = (*myStructPointer).myIntField;
就像 tempAddress = (void *)myStructPointer + offset_of_myIntField; myInt = *((int *)tempAddress);
。
这意味着如果你有一个结构数组(主要是指向数组中第一个结构的指针),索引数组会导致指针被隐式取消引用,使用->
也会导致隐式取消引用;如果你两者都做,那么你已经(隐式地)取消引用了两次指针,这太过分了(因为它不是指向结构指针的指针,也不是指向结构的指针数组)。因为您只希望在必须在一个隐式引用(数组索引)或另一个隐式取消引用(->
)之间进行选择时取消引用它;例如您可以在myInt = idCard[i].nameCardID;
或myInt = (idCard + i)->nameCardID;
之间进行选择。
当然重要的是让代码易于阅读,myInt = idCard[i].nameCardID;
比 myInt = (idCard + i)->nameCardID;
更易于阅读。
【讨论】:
我们必须不断纠正“数组是指针”的概念,而写“数组大多只是指针”会损害这种努力。它不应该出现在这个答案中。足以说明idCard[i]
是一个结构对象,而不是指向它的指针,因此使用idCard[i].member
而不是idCard[i]->member
访问结构的成员。
@EricPostpischil:这种努力是错误的(弊大于利,尤其是当人们试图了解他们的代码实际上要求 CPU/硬件做什么时),应该受到损害。
我以前从未想过这样的数组,而且我认为我还没有完全理解所有内容。但是,我认为这是一本内容丰富的读物,我将尝试在将来编写更多代码时参考这两个答案!谢谢:>【参考方案2】:
但是,我很困惑为什么编译器要求我使用点表示法而不是指针表示法......
idCard[i]
是一个结构,而不是一个指向结构的指针,所以它的成员被访问为idCard[i].<i>member</i>
,而不是idCard[i]-><i>member</i>
。
idCard[i]
是一个结构,因为每当x
是一个指针时,x[i]
就是x
指向的对象之一。它不是对象的地址。您可以使用x+i
计算对象的地址,然后您可以使用*(x+i)
引用该对象。而x[i]
其实就是这样定义的; x[i]
定义为 *(x+i)
。 (一般在表达式的情况下,<i>E1</i>[<i>E2</i>]
定义为(*((<i>E1</i>)+(<i>E2</i>)))
。)
我尝试像这样访问 Struct 的每个名称中的每个单独字符是不是错了?:(idCard[b].personName)[c]
这会起作用,但括号是不必要的。您可以使用idCard[b].personName[c]
。由于 C 语法,它已经被分组为(idCard[b].personName)[c]
。
【讨论】:
非常感谢您的澄清。但是,我仍然有点困惑。你的意思是如果x
是一个指向Struct 的指针,它会和Struct 有相同的成员,这就是为什么它可以使用x[i]
指向各种对象?
抱歉,为什么x+i
会给我对象的地址?我的印象是,如果我没有指定具体指向哪个成员/对象,指针将指向 Struct 的第一个成员?非常感谢
@Michelin_Boi:如果x
是指向结构的指针,则它没有任何成员。指针只是指向内存中的一个位置;它不包含成员。如果x
是指向结构的指针,则*x
指的是该结构。所以*x
就是那个结构,*x
有成员。所以(*x).personName
是会员。另外,x[0]
与*x
的结构相同,所以x[0].personName
是一个成员。
@Michelin_Boi: x+i
使用地址算法。如果我们有一个结构数组,比如数组A
,而x
的类型是指向该类型结构的指针,那么我们可以让x
指向数组的任何元素。例如,x = &A[3];
将x
设置为指向A[3]
。地址运算的规则是,如果x
指向元素A[t]
,那么x+i
计算一个指向A[t+i]
的指针。在x = &A[3];
之后,然后x+2
指向A[5]
。因此,如果x
指向A[0]
,那么x+i
指向A[0+i]
,等于A[i]
。所以x+i
指向A[i]
,而*(x+i)
是 A[i]
。
哦,我明白了,这很有意义!非常感谢您花时间向我解释!! :>以上是关于结构中指针表示法和点表示法之间的混淆[重复]的主要内容,如果未能解决你的问题,请参考以下文章