我不明白 pointer-pointsArray 如何从指针变为
上面 for 循环中的指针数组。我对右值和
变量中的值。如果你能包括这些,我将不胜感激
答案中的概念。
- pointsArray 在哪一行变成了指针数组? pointsArray = (int *) malloc(howMany * sizeof(int));应该只增加内存
pointsArray 的大小。
首先,让我们从基础开始。指针不是数组,数组也不是指针,它们在 C 中是两种不同的类型。数组类型在访问时转换为指向数组第一个元素的指针,如C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p3)中所提供的@
int * pointsArray;
...
pointsArray = (int *) malloc(howMany * sizeof(int));
pointsArray 是什么? (它是一个指针,用于键入int)。
那么,什么是指针?
指针只是一个普通变量,它保存着其他东西的地址作为它的值。换句话说,一个指针指向可以找到其他东西的地址。您通常会想到一个保存立即值的变量,例如int a = 5;,而指针只会保存5 存储在内存中的地址,例如int *b = &a; 将b 声明为指向int 类型的指针,并将其值初始化为5 存储在内存中的地址(例如b 指向 a -- 其中5 当前已存储)。无论指针指向什么类型的对象,它的工作方式都是相同的。
无论类型如何,指针运算对所有指针都一样,因为指针的type 控制指针运算,例如使用char * 指针,pointer+1 指向pointer 之后的下一个字节。对于int * 指针(普通的 4 字节整数),pointer+1 将指向在pointer 之后 4 字节偏移处的下一个 整数。 (所以一个指针,只是一个指针....算术由type自动处理)
- pointsArray 在哪一行变成了指针数组? pointsArray = (int *) malloc(howMany * sizeof(int));应该只增加内存
pointsArray 的大小。
回想一下,“指针不是数组,数组也不是指针。”数组声明为:
type name[CONST]; /* declares an array of type with CONST elements */
type name[var]; /* declares a VLA C99+ with var no. of elements */
type name[] = { 1, 2, 3 }; /* declares & initializes an array of 3 elements */
对比:
type *name; /* declares a pointer to type */
对于具有恒定元素数或具有初始化列表的数组,为该数组提供自动存储。可变长度数组 (VLA) 的存储类似,但在另一个段中(通常在 .bss [由符号表示的块] 中)。访问时(除非“它是sizeof 运算符、_Alignof 运算符或一元& 运算符的操作数,或者是用于初始化数组的字符串文字”)数组被转换为指向类型的指针,它指向数组对象的初始元素,而不是左值。 6.3.2.1(p3)(你会经常看到短语an “数组衰减为指针”——指的是这种转换)
(注意:它不能反向工作,指针永远不会转换为数组)
声明type *name; 将name 声明为指向type 的指针。它是未初始化的,它拥有一个不确定的地址。任何访问或以其他方式使用未初始化指针的尝试都会调用未定义行为(通常会导致分段错误)。在您可以访问内存之前,指针必须拥有一个有效的地址(例如,它必须指向有效的存储空间)。为指针提供有效存储的最简单方法是动态分配内存块并将块的起始地址分配给指针。这是在您的代码中完成的:
pointsArray = (int *) malloc(howMany * sizeof(int));
(注:malloc的return不用投,没必要。见:Do I cast the result of malloc?)
更好的方法是:
pointsArray = malloc (howMany * sizeof *pointsArray);
(pointsArray 是 int* 类型,所以 *pointsArray 是 int 类型。如果您使用取消引用的指针作为您的类型大小,您将消除类型大小错误的可能性)
在上面,malloc 保留了一个有效的内存块,保证其大小至少为howMany * sizeof *pointsArray 字节。内存块的起始地址分配给pointsArray(例如,pointsArray 现在指向该块)内存已分配存储持续时间并且在您free() 它之前一直有效,或者程序结束。您有责任保留一个指针,该指针包含内存块的起始地址,以便在不再需要时可以将其释放。
您现在最多可以在pointsArray 指向的内存块中存储howMany 整数。要访问整数的第一个地址,您可以使用 指针表示法 使用 *(pointArray + 0)(即 *pointsArray)或使用 数组索引表示法 使用 pointsArray[0] >。 (关键是要了解[] 的作用与*(name + offset) 中的'*' 相同。所以要访问第二个元素,您可以使用*(pointsArray + 1) 或pointsArray[1] 等。虽然您可以将 数组索引 表示法与指针一起使用——这不会使指针成为数组或将其转换为数组。
- 当编译器看到
&pointsArray[n]时,为什么编译器知道如何在数组中输入值?
这与scanf 的要求有关,而不是pointsArray 的任何有趣之处。想想看。从man 3 scanf() 使用%d 格式转换说明符时,scanf:
Matches an optionally signed decimal integer; the next pointer
must be a pointer to int.
因此,如果您想将一个整数读入使用int a; 声明的变量中,那么您对scanf 的使用将是:
if (scanf ("%d", &a) == 1) {
/* you have a good integer */
}
else {
/* a matching or input failure occurred */
}
对于将由scanf 放置在a 中的整数值,您必须提供一个指向a 的指针。将值放入整数 pointsArray[n] 时也没有什么不同。你如何提供一个指针(地址)pointsArray[n]? (答案:你在它前面加上运营商的一元'&'地址——&pointsArray[n])
希望这也能照顾到你的 3 号。如果您还有其他问题,请仔细查看并告诉我。