数组名的理解

数组名的再理解

先看下面的这段代码,程序会输出什么结果?

#include <stdio.h>

int main()

{

int a[5] = {1, 2, 3, 4, 5};

int *p = (int *)(&a+1);

printf("%d %d\n", *(a+1), *(p-1));

return 0;

}

答案详见本文的最后。

先来一步步分析一下数组名到底是什么,首先看一下下面这段代码:

#include <stdio.h>

int main()

{

int a[5] = {1, 2, 3, 4, 5};

int *p;

p = a;

return 0;

}

编译和运行都没有错误,说明a的值的类型直接赋给p是可以的,至少这说明了a的类型是属于可以直接赋值给p的类型中的一种,即a应该是一个指针类型的变量,而且这个指针类型变量的绝对不是int*类型的,因为在上面的程序中如果我们输出sizeof(a)和sizeof(p)的话可以看到一个输出的是20,一个输出的是4,证明这两个类型是不一样的,程序稍作修改:

#include <stdio.h>

int main()

{

int a[5] = {1, 2, 3, 4, 5};

int *p;

a = p;

return 0;

}

编译器报错误:cannot convert from ‘int *‘ to ‘int [5]‘,然而这个int [5],C语言里并没有这种类型,这个类型其实很明显就是int a[5]把a去掉之后剩下的。暂时可以这样理解,a就代表的分配的20个字节的单元整体,同时a本身的值是这20个字节的起始地址,所以a是有两层含义的。再改一下程序:

#include <stdio.h>

int main()

{

int a[5] = {1, 2, 3, 4, 5};

int *p;

a ++;

return 0;

}

编译器报错:‘++‘ needs l-value,这个错误的意思是++需要一个可以作为左值的操作对象,++唯一能够操作的就是变量,然而a根据上面的分析就是分配的一个20字节的变量,a的值也就是这20个字节变量的首地址,然而对a进行++操作却是不可以的,这个特点跟const修饰的变量时一致的。const修饰的变量相当于被赋予了只读属性,也就是说读取是可以的,写操作是非法的,所以const修饰的变量是不能做左值的,也就是不能被重新赋值的。再次修改一下例子:

#include <stdio.h>

int main()

{

int a[5] = {1, 2, 3, 4, 5};

int *p;

p = &a;

return 0;

}

编译器报错:cannot convert from ‘int (*)[5]‘ to ‘int *‘,有了这个错误问题就越来越清晰了,对a的取地址操作得到的类型是int (*)[5],即一个数组指针,也就是说这个时候取地址操作对a的理解是一个20个字节的整体(5个int型的单元)。然而当采用p=a这种使用方法的时候,使用的是a的第二种理解方法就是取的是a的值,也就是这20个字节的起始地址。

再由C语言的优先级来分析最开始的题目,int *p = (int *)(&a+1)这条语句,&的优先级高于+,所以等同于int *p (int *)((&a)+1),这下来逐步分析,&a得到的是一个5个int型单元的数组指针,&a+1得到的就是这个指针加1的结果,也就是说现在的指针会指向a这20个字节后的第一个单元,这个单元的地址再被强制转换为int *类型赋值给p,所以p也就指向了a的20个字节后的第一个单元,所以*(p-1)取到的值就应该是p的前一个单元,也就是a的5个单元中最后的一个单元的值。所以得到最开头的程序输出为:2
5

时间: 2024-11-08 22:00:53

数组名的理解的相关文章

关于理解指针数组,数组指针,数组名,二维数组的一些技巧。

/*************关于数组名***************/ int a[3] = {1, 2, 3} 1.数组名代表数组第一个元素的地址,注意,不是数组地址(虽然值相等),是数组第一个元素地址,a 等同于 &a[0]; a+1是第二个元素的地址.比第一个元素地址a(或者&a[0])超出了一个整型指针的大小,在这里是4个字节(byte) cout << a << endl;会输出数组第一个元素地址. 2.取址符号&. &a是数组的地址,注意

对于C语言中数组名是指针的理解

我们都知道,c语言中数组名是一个指针,比如下面这段代码 #include<iostream>using namespace std;int main(){ int a[4]={1,2,3,4}; for(int i=0;i<4;i++) {  cout<<*(a+i);//*(a+i)和a[i]是等价的.  cout<<endl; } return 0;} 但是看下面这个代码 #include<iostream>using namespace std;

数组名和指针的深入理解(C++)

指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用.于是乎,很多程序设计者就被搞糊涂了. 魔幻数组名 请看程序(本文程序在WIN32平台下编译): #include <iostream> using namespace std; int main() { char str[10]; char* pStr = str; cout << "sizeof(str): \t" << sizeof(str) <&

C语言之数组名的含义

一:一维数组 int a[5]; a:就是数组名.a做左值时表示整个数组的所有空间(10×4=40字节),又因为C语言规定数组操作时要独立单个操作,不能整体操作数组,所以a不能做左值:a做右值表示数组首元素(数组的第0个元素,也就是a[0])的首地址(首地址就是起始地址,就是4个字节中最开始第一个字节的地址).a做右值等同于&a[0]; a[0]:表示数组的首元素,也就是数组的第0个元素.做左值时表示数组第0个元素对应的内存空间(连续4字节):做右值时表示数组第0个元素的值(也就是数组第0个元素

C语言中对数组名取地址

在C/C++中,数组名相当于一个指针,指向数组的首地址.这里"相当于"不代表等于,数组名和指针还是有很多区别的,这个在<C陷阱与缺陷>里有详尽的讲述.而这里要说的是对于数组名取地址的这么一个操作. 如果声明有如下数组: int arr[5]; 那么,&arr这个操作得到了什么值呢? 如果简单的认为arr就是一个指向数组首地址的指针的话,那么很自然会想到&arr得到的是一个指向存放arr这个指针的指针,也就是一个二级指针,然而事实却并不是这样. 观察以下代码:

6、JAVA基础-二维数组 及 面向对象理解

1:二维数组(理解) (1)元素是一维数组的数组. (2)格式: A:数据类型[][] 数组名 = new 数据类型[m][n]; B:数据类型[][] 数组名 = new 数据类型[m][]; C:数据类型[][] 数组名 = new 数据类型[][]{{...},{...},{...}}; D:数据类型[][] 数组名 = {{...},{...},{...}}; (3)案例(掌握): A:二维数组的遍历 B:二维数组的求和 C:杨辉三角形 2:两个思考题(理解) (1)Java中的参数传递

C 语言中的左值和右值。以及对比数组名和指针取数组元素的区别。

左值:出现在赋值符左边的符号有时称为左值. 右值:出现在赋值符右边的符号有时称为右值. 编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址.相反,存储于变量中的值(它的右值)只有在运行时才可知.如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器. 可以看到,每个符号的地址在编译时可知. 对比一下几个式子: //常规变量 int a=1;//这里a作为左值出现,代表的是地址,即在a表示的这个内存地址存入数值1.即a代表的内

【转】C语言-&gt;数组名与指针

以下内容转自: http://bbs.csdn.net/topics/390733584 感觉对自己有用,收藏了.如果转帖,请注明如上出处.多谢! 看到一篇关于C语言指针的文章,正好最近在看<C和指针>就去看了一下.<一道 C 语言指针访存题目的引申>,里面的第一个题目就把我难住了. 帮助123456789 #include <stdio.h>   int main() {     int a[5] = {1, 2, 3, 4, 5};     int *pa = (i

[skill] C语言数组名到底是个啥

1. 正常情况下,数组名是个地址常量. 2. sizeof(数组名)的时候,数组名就代表数字名,其类型为 type array[], 返回数组元素个数. 3. 除了2的情况以外,可以理解为一个指针常量 !? 参考: http://www.cnblogs.com/kalo1111/p/3285955.html http://c.biancheng.net/cpp/html/492.html