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个元素对应的内存空间中存储的那个数)

&a:就是数组名a取地址,字面意思来看就应该是数组的地址。&a不能做左值(&a实质是一个常量,不是变量因此不能赋值,所以自然不能做左值。);&a做右值时表示整个数组的首地址。

&a[0]:字面意思就是数组第0个元素的首地址(搞清楚[]和&的优先级,[]的优先级要高于&,所以a先和[]结合再取地址)。做左值时表示数组首元素对应的内存空间,做右值时表示数组首元素的值(也就是数组首元素对应的内存空间中存储的那个数值)。做右值时&a[0]等同于a。

总结:

    1:&a和a做右值时的区别:&a是整个数组的首地址,而a是数组首元素的首地址。

这两个在数字上是相等的,但是意义不相同。意义不相同会导致他们在参与运算的时候有不同的表现。

    2:a和&a[0]做右值时意义和数值完全相同,完全可以互相替代。

    3:&a是常量,不能做左值。

    4:a做左值代表整个数组所有空间,所以a不能做左值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
int  main ( void )
{
     int  a[5]={1,2,3,4,5};
     int  *p1;
     int  (*p2)[5];
     printf ( "p1 = %p \n" ,p1);
     printf ( "p2 = %p \n" ,p2);
     p1 = a;
     p2 = &a;
     printf ( "p1 = %p \n" ,p1);
     printf ( "(p1+1) = %p \n" ,(p1+1));
     printf ( "p2 = %p \n" ,p2);
     printf ( "(p2+1) = %p \n" ,(p2+1));
     return  0;
}

/******运行结果

p1 = 0xbfbcda54

p2 = 0xbfbcda5c

p1 = 0xbfbcd99c

(p1+1) = 0xbfbcd9a0

p2 = 0xbfbcd99c

(p2+1) = 0xbfbcd9b0

*******************/

/*********分析:*****

1:p1 p2定义的时候被没有进行初始化,所以属于野指针。

2:p1 = a ,a数组名做右值表示首元素首地址,而数组a是int类型,所以首元素首地址中存放的也是int类型的数所以类型匹配。也就是说p1是指向int类型的数的指针

3:p1+1=p1+4 p1指向的数组的首元素首地址,相当于p1指向了数组内部,所以p1+1其实就是p1+sizeof(数组类型)

4:p2 = &a p2的定义是int(*p2)[5]可以理解为是一个指向int [5]类型的指针,所以p2是一个指向数组的指针

而&a是数组名取地址,表示的就是数组的地址(表示这个地址存放的就是一个数组类型),所以p2和&a的类型匹配。

5:p2 + 1 = p2 + 20   因为p2在定义的时候就被定义为指向一个int [5]类型的地址,所以

p2+1 = p2+sizeof(int [5]);

6:指针+1实际上就是指针+siezof(指针类型),这个其实是在定义的时候就已经确定了,因为在初始化的时候

指针指向的类型一定要和指针定义时候的类型匹配。

例如

char a[5];

int *p;        //p是一个指向int类型的指针

p = a ;则类型就不匹配,编译不通过。但是假如这样可以成功初始化,那么指针再运算的时候它的指向就会出错

比如开始p = a 的地址是0xb2000000,那么p+1 则为0xb2000004,而0xb2000004实际上是a[3]而不是a[1]这样就

无法进行运算了,所以指针类型的匹配主要是为了能够进行运算。

*******************************************/


二:二维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
int  main( void )
{
     int  a[2][5];
     int  *p1;
     int  (*p2)[5];
     int  b = 5;
     //p1 = a;  //编译报错,类型不匹配
     p2 = a;   //编译不报错,类型匹配
     printf ( "a = %p \n" ,a);
     printf ( "&a[0] = %p \n" ,&a[0]);
     printf ( "p2 = %p \n" ,p2);
     printf ( "p2 + 1 = %p \n" , p2+1);   //这里进行p2 + 1,p2的值并不变
     printf ( "p2 = %p \n" ,p2);
     printf ( "*(p2 + 1)+1 = %p \n" , *(p2 + 1)+1);
     return  0;
}

/**********运行结果************

a = 0xbfeaebc8

&a[0] = 0xbfeaebc8

p2 = 0xbfeaebc8

p2 + 1 = 0xbfeaebdc

*(p2 + 1)+1 = 0xbfeaebe0

**************************/

/************分析*****

1:p2是int* [5] 类型是一个指向int [5]的指针,

2:数组名做右值表示的是数组的首元素首地址,二维数组的数组名表示的是第一维的地址,类型也是int [5]

所以和p2的类型匹配

3:p2+1 = p2 +20 原因也就是p2指向的是int [][5],所以p2 + 1实际上+是指向了a[1][]也就是第一维的第二个元素。

4:*(p2 + 1)+1 =(p1+1)+4 ,指向是的a[1][1] 也就是说*(*(p+i)+j)等于a[i][j]。


*/


本文转自 菜鸟养成记 51CTO博客,原文链接:http://blog.51cto.com/11674570/1927647

相关文章
|
9月前
|
存储 程序员 C语言
C语言:数组名
C语言:数组名
|
4月前
|
存储 编译器 C语言
C语言:数组名作为类型、作为地址、对数组名取地址的区别
在C语言中,数组名可以作为类型、地址和取地址使用。数组名本身代表数组的首地址,作为地址时可以直接使用;作为类型时,用于声明指针或函数参数;取地址时,使用取地址符 (&),得到的是整个数组的地址,类型为指向该类型的指针。
|
4月前
|
编译器 C语言
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
|
8月前
|
网络协议 C语言 C++
C语言的数组名是什么
C语言的数组名是什么
|
C语言
C语言 --- 一维数组名的理解
C语言 --- 一维数组名的理解
134 0
|
C语言
【C语言】规范掌握C语言函数|数组名的妙用|指针快速入门|综合使用小案例
【C语言】规范掌握C语言函数|数组名的妙用|指针快速入门|综合使用小案例
79 0
|
算法 C语言
13【C语言 & 趣味算法】分糖果 问题。(数组名作为函数形参,亦即:形参数组名作 指针变量)
13【C语言 & 趣味算法】分糖果 问题。(数组名作为函数形参,亦即:形参数组名作 指针变量)
13【C语言 & 趣味算法】分糖果 问题。(数组名作为函数形参,亦即:形参数组名作 指针变量)
|
C语言
c语言 数组名和下标运算符
前面我们稍微提过数组的属性:数组名就是首元素的首地址,即 &a[0]==a; 则:int *p = &a[0] ; 也可写成 int *p = a ; 两者一摸一样,平时都是用第二种,因为写起来比较方便。
186 0
【C语言】数组名是什么
【C语言】数组名是什么
【C语言】数组名是什么