使用指针访问数组和通过指针访问非数组变量之间的区别是什么

时间:2016-09-08 21:06:53

标签: c arrays pointers

我试图更深入地学习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提供?我有什么好的资源可以用来更好的解释吗?

1 个答案:

答案 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 *宽(在我的系统上为真),因此输出可能会出现乱码。