我试图更深入地学习C语言。我写了下面显示的代码。
#include "includes.h"
int main() {
char *array[1];
array[0] = "cloud";
char *ll[1];
ll[0] = array[0];
int n = 20, *pointer; // actual and pointer decaration
pointer = &n; // assign the memory address of int n to pointer
printf("the address of the variable in pointer is: %x\n", pointer);
printf("the value of *pointer is %d\n", *pointer);
printf("the value of &pointer is %x\n", &n);
//return 0;
// to access the value provided by a pointer, you would use *pointer
// accessing an array directly
printf("value of array[0] %s\n", array[0]);
printf("address of &array[0] %x\n", &array[0]);
// accessing array through the pointer ll
printf("value of *ll %s\n", *ll);
printf("address of ll %x\n", ll);
printf("pointer: %p\n", (void*) pointer); //inclusion from @chux
}
头文件" includes.h"包含以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#define DEF1 20
#define DEF2 2
这是程序输出,来自我的Bash终端:
[carl@sparknohss c]$ ./pointers.bin
the address of the variable in pointer is: 4a8c27dc
the value of *pointer is: 20
the value of &pointer is: 4a8c27dc
value of array[0]: cloud
address of &array[0]: 4a8c27f0
value of *ll: cloud
address of ll: 4a8c27e0
pointer: 0x7ffc4a8c27dc
[carl@sparknohss c]$
我发现,当访问指向非数组的指针和访问指向数组的指针时,至少我认为存在差异。是否有人可以更详细地解释这一点?
此外,%x
和%p
之间的区别是什么,除了&#39; 0x7ffc&#39;前缀由%x
提供?我有什么好的资源可以用来更好的解释吗?
答案 0 :(得分:2)
我发现,当访问指向非数组的指针和访问指向数组的指针时,至少我认为存在差异。是否有人可以更详细地解释这一点?
处理数组和指针对象时存在一些差异。
将代码搁置一秒钟,假设您有声明
int arr[10];
这会创建一个足以容纳10个整数的数组arr
;它在记忆中如此布局:
+---+
arr: | | arr[0]
+---+
| | arr[1]
+---+
...
+---+
| | arr[9]
+---+
这里有一件事显而易见 - 数组的第一个元素(&arr[0]
)的地址将与整个数组对象(&arr
)的地址相同。表达式&arr[0]
和&arr
将具有相同的值,但其类型将不同 - &arr[0]
的类型将是&#34;指向int
&#34; (int *
),而&arr
的类型将是&#34;指向 10元素数组 int
&#34; (int (*)[10]
)。
现在出现皱纹 - 除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,&#34; <{1}}&#34;的数组的表达式;将被转换(&#34;衰减&#34;)到类型为&#34的表达式;指向T
&#34;的指针,并且表达式的值将是第一个元素的地址。阵列。
这意味着表达式 T
也计算到数组第一个元素的地址,就像arr
和{{ 1}};它&#34;衰变&#34;来自类型&#34; 10个元素的&arr[0]
&#34; to&#34;指向&arr
&#34;的指针(与int
相同的类型)。
这肯定与常规指针变量的行为不同。给定
int
表达式&arr[0]
使不为您提供与int *ptr;
相同的值 - 它为您提供ptr
中存储的值的值。
在
行中返回您的代码一秒钟&ptr
字符串文字 ptr
本身就是一个数组表达式 - 它具有类型&#34; 6元素数组array[0] = "cloud";
&#34; (计算0终止符)。由于它不是"cloud"
或一元char
运算符的操作数,也不是用于在声明中初始化另一个数组,因此表达式从类型&#34;数组转换为{{1 }}&#34; to&#34;指向sizeof
&#34;的指针,表达式的值是字符串中第一个字符的地址。由于您将&
声明为char
的数组,因此可行; char
的类型为array
。
那么,为什么数组表达式&#34;衰变&#34;指针表达式?
数组索引操作char *
定义为array[0]
- 给定地址值,偏移char *
个元素(不是字节 )从该地址并取消引用结果。这是来自B编程语言的延续,C编译语言是从C语言派生的,并且在设置数组对象时在内部使用了指针。 C摆脱了内部指针,但保留了下标语义。因此,要使a[i]
在C中工作,首先必须将*(a + i)
转换为指针值。请注意,这意味着您可以在指针类型上使用i
运算符 - a[i]
和a
将为您提供相同的结果(事物[]
指向的值) 。
因此,如果您打印出以下表达式:
pointer[0]
你应该看到所有三个相同的值 - *pointer
的第一个元素的地址。如果你打印出表达式
pointer
你应该看到printf( "&array[0] = %p\n", (void *) &array[0] );
printf( "array = %p\n", (void *) array );
printf( "&array = %p\n", (void *) &array );
字符串文字的第一个字符的地址。
如果您打印表达式
array
你应该看到字符串printf( "array[0] = %p\n", (void *) array[0] );
。请记住,"cloud"
转换说明符期望其对应的参数是指向printf( "array = %s\n", array );
的指针,它将打印从该地址开始的字符序列,直到它看到0终止符。
如果您打印表达式
cloud
您会看到字符%s
- char
字符串中的第一个字母。请注意,printf( "*array[0] = %c\n", *array[0] );
与c
相同。要打印"cloud"
,请编写
*array[0]
如果您打印表达式
array[0][0]
你应该肯定看到不同的值,因为l
不是数组对象。
此外,%x和%p
之间有什么区别
printf( "array[0][1] = %c\n", array[0][1] );
期望其对应的参数具有类型printf( "pointer = %p\n", (void *) pointer );
printf( "&pointer = %p\n", (void *) &pointer );
,并以十六进制格式化输出。
pointer
期望其对应的参数具有类型%x
,并以实现定义的方式格式化输出(通常是十六进制,但它不必是)。
你不想要使用unsigned int
(或%p
以外的任何东西)来打印指针值。首先,指针值可能比void *
宽(在我的系统上为真),因此输出可能会出现乱码。