数组衰变成指针

6
请帮我理解以下程序。
#include<stdio.h>
int main()
{
    int a[7];
    a[0] = 1976;
    a[1] = 1984;
    printf("memory location of a: %p", a); 
    printf("value at memory location %p is %d", a, *a); 
    printf("value at memory location %p is %d", &a[1], a[1]);
    return 0;
}

&a[1]&a+1,它们是相同的还是不同的?

#include <stdio.h> 
int main() 
{
    int v[10];
    int **p; 
    int *a[5];
    v[0] = 1234;
    v[1] = 5678;
    a[0] = v; 
    a[1] = v+1;
    printf("%d\t%d\t%d\t%d\n", *a[0],*a[1],a[0][0],**a);
    printf("%d\n", sizeof(v));
    return 0;
} 

我想知道在内存中如何表示*a[5]*a是否是指向a [0]、a [1]、a [2]、a [3]、a [4]的基指针?

#include<stdio.h>

int main()
{
    int v[10];
    int **p;
    int (*a)[10];
    a=&v;
    printf("%d\n",*a);
        return 0;
}

a=v; // 为什么会出错?这里的v是否会衰减为*v。然后,&v是否会衰减为(*)[]v?&表示常量指针。在这里,如何将一个常量指针设置为非常量指针而不需要类型转换?

数组存储在内存中的哪里?它是存储在数据段中吗?

#include<stdio.h>

int main()
{
    int carray[5]={1,2,3,4,5};
    printf("%d\n",carray[0]);
    printf("%d\t%d\t%d\n",sizeof(carray),sizeof(&carray),sizeof(&carray[0]));
    return 0;
}

EDITED:

我看了一些文章,它们指出数组名只有在sizeof&两种情况下才不能被解析为指针。但在上面的程序中,sizeof(&carray)的大小为4。&carray衰减为(*)[]carray,因为它是一个右值。

因此,数组名不能在sizeof&两个条件下衰减为指针的说法在这里不成立。


要打印size_t类型的值,比如sizeof的结果,要么使用%zu(如果编译器支持),要么将该值转换为其他类型并使用适合该类型的格式。%d需要int类型的参数,如果给它一个size_t类型的参数,可能会导致严重错误。要打印指针值,必须将该值转换为(void*)并使用%p;不同的指针类型通常不兼容。例如:printf("obj has size %lu and address %p\n", sizeof obj, (void*)&obj); - Keith Thompson
阅读comp.lang.c FAQ的第6节。请理解数组和指针是两个非常不同的东西;不要听任何人告诉你它们是等价的。 - Keith Thompson
@Keith:谢谢Keith。我会阅读那些部分的。 - Angus
但是在上面的程序中,sizeof(&carray) 的大小为4,并且&carray会衰减为(*)[]carray,因为它是一个右值。不,它没有衰减。取地址运算符的结果始终是一个地址。也就是说,虽然carray是一个数组,但&carray是它的地址。在您的计算机上,地址可能仅有4个字节长,这可能令人失望。因此,sizeof(&carray)产生地址大小为4。没有涉及到衰减。我相当确定sizeof(*&carray)产生20,显示数组大小通过前后传递得到了完好保留。 - Peter - Reinstate Monica
2个回答

5

&a[1]&a+1。它们是相同的还是不同的?

不同。&a[1] 等同于 (a+1)。一般来说,x[y] 的定义等同于 *(x+y)

我想知道 *a[5] 在内存中是如何表示的。是否 *a 是一个基指针,它指向 a[0]、a[1]、a[2]、a[3]、a[4]

在你的第二个示例中,a 是指针数组。 *a[i] 是对象的值,其地址存储为数组中的第 i 个元素。在这种情况下,*a 等同于 a[0],它是数组的第一个元素(指针)。

a=v //为什么会出现错误

因为在你的最后一个示例中,a 是指向数组的指针。如果你想要对 a 赋值,那么你需要赋值给数组 v 的地址(或任何其他正确维度的数组)。

a = &v;

很高兴你致力于理解事物,但没有什么比一本好的C语言书籍更能帮助你。

希望这对你有所帮助。


-3
处理指针时,你需要知道的一些东西是:
int *a and int a[]

这是一个数组的声明,唯一的区别在于在a[]中你必须声明它的常量大小,*a则给了你灵活性,它可以指向大小为1到无限大的数组

int *a[] and int **a

这是一个声明数组的语句,有时被称为矩阵,唯一的区别在于在*a[]中,您需要声明a[]将包含多少个指针的数组,**a给您灵活性,它可以指向任何您想要分配给它的数组的数组。

通常情况下: 当在变量上添加&时,您正在将*添加到其类型定义中:

int a;

&a -> &(int)=int*

当在变量上添加*时,您会从其类型定义中减少一个*。

int *a;

*a -> *(int*)=int

int *a;
&a - the Address given to the pointer a by the system(pointer of pointer = **a)
&a+1 - the Address to the beginning of the array + 1 byte
&a[1] == &(a+1) - the Address to the beginning of the array + 1 size of int

int **a;
*a == a[0] - the Address of the first Array in the array of arrays a
*a[0]==a[0][0] - the first int of first array

int *a, b[5];
*a=*b - ERROR because a points at garbage to begin with
a=b - a points at array b

如果你还有其他问题,可以问我,我会编辑这个答案。


int *a 声明一个指针对象,它并不声明一个整形指针对象。 int a[] 声明一个数组对象,它并不声明一个指针对象。 数组不是指针,指针也不是数组。 - Keith Thompson
你可以声明 int a[] 和 int *b,并且使用 b=a 和 a=b 这样的命令,这就是我所说的,你可以尝试一下。 - Ofek Ron
2
我建议你尝试一下。如果你将int a[]声明为参数,那么它实际上是一个指针声明,而不是数组声明。在任何其他情况下,int a[]int a[N]a声明为数组,并且数组名不能出现在赋值的左侧。 - Keith Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接