int main(void) {
int* b[3] = {1, 2, 3}; // b is an array of pointers to integer
printf("%d", b); // b = address of array of pointers
printf("\n%d", *b); // *b should be address of the place where 1 is stored ....right?
printf("\n%d", *(b+1)); // similarly *(b+1) should be address of place where 2 is stored
printf("\n%d", *(b+2)); // and so on... But they print 1,2 and 3
printf("\n%d", b[0]); // prints 1 . No problem!
printf("%d", *(*(b+1)+2)); // Also why does this give segmentation fault?
//PLUS I GET THIS WARNING : array_of_pointers2.c:5:13: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
//PLEASE EXPLAIN !! I think I have misunderstood something.
return 0;
}
答案 0 :(得分:4)
您的代码存在许多问题,主要来自int *b[3]
没有正确的初始值设定项的事实。对于{ 1, 2, 3 }
的数组,int
是正常的,而不是int *
的数组,正如编译器正确诊断的那样:
array_of_pointers2.c:5:13: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
为了与古代代码兼容,编译器仅发出警告,但此类警告表示必须更正的错误。我强烈建议您使用-Wall -Werror
编译代码,让编译器产生错误,而不仅仅是针对此类问题的警告。
访问地址1
,2
或3
很可能有未定义的行为,这会在您的系统上采用分段错误的形式。
要初始化指针数组,您可以指定int
变量的地址。
以下是更正后的版本:
#include <stdio.h>
int main(void) {
int x = 1, y = 2, z = 3;
int *b[3] = { &x, &y, &z }; // b is an array of pointers to integer
printf(" b: %p\n", (void*)(b)); // b = address of array of pointers
printf(" *b: %p\n", (void*)(*b)); // *b is the address of variable x that has a value of 1
printf(" *(b+1): %p\n", (void*)(*(b+1))); // similarly *(b+1) is the address of y where 2 is stored
printf(" *(b+2): %p\n", (void*)(*(b+2))); // and so on...
printf(" *b[0]: %d\n", *b[0]); // prints 1. No problem!
printf("*(*(b+1)): %d\n", *(*(b+1))); // prints 2
// accessing *(*(b+1)+2) would have undefined behavior because b[1] is
// not the address of an array of at least 3 ints.
printf(" b[2][0]: %d\n", b[2][0]); // prints 3
return 0;
}
请注意,指针无法使用%d
打印,因为它具有未定义的行为,因为指针可能会以不同的方式从整数传递到printf
。格式为%p
,指针应转换为(void*)
,以实现完全的可移植性。
答案 1 :(得分:3)
数组在地址空间中连续存储。 它们的分配是静态的,这意味着你不能在运行时为它分配空间,因此它们存储在不同的内存区域 - 堆栈。
数组通过元素数量乘以数据类型的大小来确定其大小(因为您已经将变量打包了n次)。
大小是它在内存中占用的空间(以字节为单位)。它不应该与数组的长度混淆,后者是数组中的元素数量。例如int arr[2]
通常是8个字节(sizeof(int[2])
),但是是一个长度为2的数组。
有许多方法可以初始化数组,但有两种方法可以取消引用它。
一种是使用索引运算符[]
,另一种是使用*
取消引用它衰减的指针示例:
int arr[3];
arr[0] = 40;
*arr = 40;
arr[2] = 40; // <-- this is functionally equivalent to..
*(arr + 2) = 40; // <--this (Note the pointer arithmetic involved)
int* arr[3]
- 这是一个int指针数组。
索引运算符具有非常高的优先级,高于*
要解决这个问题,并基本上创建一个指向3个元素数组的指针,可以使用括号来定义评估的优先级:
int (*arr)[3];
Bracket的第二个用例是制作一个&#34;派生类型&#34; - 一个功能。 ([]
,*
,()
用于定义派生类型)
一个字符数组
char arr[3] = {'a', 'b', 'c'}
char arr[] = {'a', 'b', 'c'}
char arr[3] = "hi" // Note this is a string, not array of characters anymore
要初始化int指针数组的第一个元素,你可以很好地执行此操作:
char ch1 = 'a';
char* arr[3] = { &ch1 };
最后,初始化一个指向3个字符数组的指针:
char arr[3] = {'a', 'b', 'c'};
char (*arr2)[3] = arr;
答案 2 :(得分:1)
int* b[3] = {1, 2, 3};
这样存储如下:
b
+-----+
| 1 |
+-----+
| 2 |
+-----+
| 3 |
+-----+
你要求一个包含1,2和3的数组,你得到一个包含1,2和3的数组。它不创建包含1,2和3的单独变量然后放入指向数组中那些变量的指针。不,它只是在数组中放入1,2和3并继续。
警告是因为直接写入内存地址非常罕见且通常是错误的。内存地址1是什么?如果我知道,该死的。可能它甚至不是一个有效的地址,所以当你执行*b[0]
它只会崩溃。
*b
与b[0]
相同,*(b+1)
与b[1]
相同,依此类推。所以这些只是获取数组中的“指针” - 而不是他们指向的东西。
*(*(b+1)+2)
段错误,因为它访问地址10(在32位系统上)。可能10也不是任何有效的地址。所以你得到了一个段错误。