对数组的引用与对数组指针的引用
Reference to Array vs reference to array pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main(){
char array[10] = {'j','o','h','n'};
char * bla = array;
check(&bla);
check(&array);
}
输出:
word is john
RUN FINISHED; Segmentation fault; core dumped;
第一个有效,第二个无效。我不明白为什么会这样。
对于 check(&bla);
你发送 pointer to pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr); // works fine for pointer to pointer
printf("word is %s\n",word);
}
这工作正常。
但是,对于 check(&array);
,您仅传递指针
void check(void* elemAddr){
char* word = *((char**)elemAddr); // This is not working for pointer
char* word = *(char (*)[10])(elemAddr); // Try this for [check(&array);]
printf("word is %s\n",word);
}
完整代码--
check(array);
的代码:
void check(void* elemAddr){
char* word = *(char (*)[10])(elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
check((char*)array);
return 0;
}
check(&bla);
的代码:
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
char* bla = array;
check(&bla);
return 0;
}
问题是,当我们执行 &array
时,我们从 char [10]
得到 char (*)[10]
,而不是 char **
。
在我们做实验之前,我要强调的是,当我们将数组作为参数传递给函数时,C 实际上将数组转换为指针。大桶数据没有复制。
因此,int main(int argc, char **argv)
与 C 中的 int main(int argc, char *argv[])
相同。
这使我们可以使用简单的 printf
.
打印数组的地址
我们来做个实验:
char array[] = "john";
printf("array: %p\n", array);
printf("&array: %p\n", &array);
// Output:
array: 0x7fff924eaae0
&array: 0x7fff924eaae0
了解这些之后,让我们深入研究您的代码:
char array[10] = "john";
char *bla = array;
check(&bla);
check(&array);
bla
是 char *
,&bla
是 char **
。
然而,array
是char [10]
,而&array
是char (*)[10]
而不是char **
。
因此,当您将 &array
作为参数传递时,char (*)[10]
在作为参数传递时就像 char *
一样,如上所述。
因此 **(char **) &bla == 'j'
而 *(char *) &array == 'j'
。做一些简单的实验,你就会证明这一点。
并且您正在将 void *elemAddr
转换为 char **
并尝试顺从它。这仅适用于 &bla
,因为它是 char **
。 &array
将导致段错误,因为 "john" 在您进行转换时被解释为地址。
一个问题是您的 char 数组不一定要以 null 结尾。由于 array
是在堆栈上本地分配的自动变量,因此不能保证它是清零内存。因此,即使您正在初始化前 4 个字符,后 6 个字符仍未定义。
然而...
您问题的简单答案是 &bla != &array
因此您的 check() 函数假设它将在 2 个不同的地址找到以 null 结尾的字符数组。
下列等式为真:
array == &array // while not the same types exactly, these are equivalent pointers
array == bla
&array == bla
*bla == array[0]
&bla
永远不会等于你想要的任何东西,因为该语法引用本地堆栈上 bla
变量的 地址 并且与处理它的值(或它指向的内容)。
希望对您有所帮助。
这不是对您问题的直接回答,但可能对您以后有所帮助。
数组不是指针:
type arr[10]
:
使用了 sizeof(type)*10
字节
arr
和&arr
的值必然相同
arr
指向一个有效的内存地址,但不能设置为指向另一个内存地址
type* ptr = arr
:
使用了额外的 sizeof(type*)
字节
ptr
和&ptr
的值通常是不同的,除非你设置ptr = (type*)&ptr
ptr
可以设置为同时指向有效和无效的内存地址,次数不限
关于您的问题:&bla != bla == array == &array
,因此 &bla != &array
。
C 规范说 array 和 &array 是相同的指针地址。
在将数组传递给函数时使用数组名称会根据 C 规范(强调我的)自动将参数转换为指针。
6.3.2.1-4
Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
因此调用 func(array) 会导致将指向 char[] 的指针传递给函数。但是在数组上使用寻址运算符有一种特殊情况。由于数组的类型为 "array of type",因此它属于规范的 'Otherwise' 类别(强调我的)。
6.5.3.2-3
The unary & operator yields the address of its operand. If the operand
has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the
operand is the result of a unary * operator, neither that operator nor
the & operator is evaluated and the result is as if both were omitted,
except that the constraints on the operators still apply and the
result is not an lvalue. Similarly, if the operand is the result of a
[] operator, neither the & operator nor the unary * that is implied by
the [] is evaluated and the result is as if the & operator were
removed and the [] operator were changed to a + operator. Otherwise,
the result is a pointer to the object or function designated by its
operand
所以调用 func(&array) 仍然会导致将单个指针传递给函数,就像调用 func(array) 一样,因为 array 和 &array 都是相同的指针值。
常识会让您相信 &array 是指向数组第一个元素的双指针,因为使用 & 运算符通常会这样。但是数组不同。因此,当您将传递的数组指针取消引用为指向数组的双指针时,您会遇到分段错误。
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main(){
char array[10] = {'j','o','h','n'};
char * bla = array;
check(&bla);
check(&array);
}
输出:
word is john
RUN FINISHED; Segmentation fault; core dumped;
第一个有效,第二个无效。我不明白为什么会这样。
对于 check(&bla);
你发送 pointer to pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr); // works fine for pointer to pointer
printf("word is %s\n",word);
}
这工作正常。
但是,对于 check(&array);
,您仅传递指针
void check(void* elemAddr){
char* word = *((char**)elemAddr); // This is not working for pointer
char* word = *(char (*)[10])(elemAddr); // Try this for [check(&array);]
printf("word is %s\n",word);
}
完整代码--
check(array);
的代码:
void check(void* elemAddr){
char* word = *(char (*)[10])(elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
check((char*)array);
return 0;
}
check(&bla);
的代码:
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
char* bla = array;
check(&bla);
return 0;
}
问题是,当我们执行 &array
时,我们从 char [10]
得到 char (*)[10]
,而不是 char **
。
在我们做实验之前,我要强调的是,当我们将数组作为参数传递给函数时,C 实际上将数组转换为指针。大桶数据没有复制。
因此,int main(int argc, char **argv)
与 C 中的 int main(int argc, char *argv[])
相同。
这使我们可以使用简单的 printf
.
我们来做个实验:
char array[] = "john";
printf("array: %p\n", array);
printf("&array: %p\n", &array);
// Output:
array: 0x7fff924eaae0
&array: 0x7fff924eaae0
了解这些之后,让我们深入研究您的代码:
char array[10] = "john";
char *bla = array;
check(&bla);
check(&array);
bla
是 char *
,&bla
是 char **
。
然而,array
是char [10]
,而&array
是char (*)[10]
而不是char **
。
因此,当您将 &array
作为参数传递时,char (*)[10]
在作为参数传递时就像 char *
一样,如上所述。
因此 **(char **) &bla == 'j'
而 *(char *) &array == 'j'
。做一些简单的实验,你就会证明这一点。
并且您正在将 void *elemAddr
转换为 char **
并尝试顺从它。这仅适用于 &bla
,因为它是 char **
。 &array
将导致段错误,因为 "john" 在您进行转换时被解释为地址。
一个问题是您的 char 数组不一定要以 null 结尾。由于 array
是在堆栈上本地分配的自动变量,因此不能保证它是清零内存。因此,即使您正在初始化前 4 个字符,后 6 个字符仍未定义。
然而...
您问题的简单答案是 &bla != &array
因此您的 check() 函数假设它将在 2 个不同的地址找到以 null 结尾的字符数组。
下列等式为真:
array == &array // while not the same types exactly, these are equivalent pointers
array == bla
&array == bla
*bla == array[0]
&bla
永远不会等于你想要的任何东西,因为该语法引用本地堆栈上 bla
变量的 地址 并且与处理它的值(或它指向的内容)。
希望对您有所帮助。
这不是对您问题的直接回答,但可能对您以后有所帮助。
数组不是指针:
type arr[10]
:使用了
sizeof(type)*10
字节arr
和&arr
的值必然相同arr
指向一个有效的内存地址,但不能设置为指向另一个内存地址
type* ptr = arr
:使用了额外的
sizeof(type*)
字节ptr
和&ptr
的值通常是不同的,除非你设置ptr = (type*)&ptr
ptr
可以设置为同时指向有效和无效的内存地址,次数不限
关于您的问题:&bla != bla == array == &array
,因此 &bla != &array
。
C 规范说 array 和 &array 是相同的指针地址。
在将数组传递给函数时使用数组名称会根据 C 规范(强调我的)自动将参数转换为指针。
6.3.2.1-4
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
因此调用 func(array) 会导致将指向 char[] 的指针传递给函数。但是在数组上使用寻址运算符有一种特殊情况。由于数组的类型为 "array of type",因此它属于规范的 'Otherwise' 类别(强调我的)。
6.5.3.2-3
The unary & operator yields the address of its operand. If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator. Otherwise, the result is a pointer to the object or function designated by its operand
所以调用 func(&array) 仍然会导致将单个指针传递给函数,就像调用 func(array) 一样,因为 array 和 &array 都是相同的指针值。
常识会让您相信 &array 是指向数组第一个元素的双指针,因为使用 & 运算符通常会这样。但是数组不同。因此,当您将传递的数组指针取消引用为指向数组的双指针时,您会遇到分段错误。