一维数组、二维数组、字符数组的&、sizeof等操作

   一 前提知识

1、sizeof是一个运算符,sizeof(a)计算的是a这种变量类型或结构体所占的字节数

2、变量名一旦进行了移位操作,那么他就退化成了指针

3、数组名和对数组名取地址的值是一样的,但是含义不一样

4、数组名和指针的区别

    指针是一个变量,变量的值是另外一个变量的地址。那么,既然指针是变量,那么指针必然有自己的存储空间,只不过是该存储空间内的值是一个地址值,而不是别的内容。
    数组名没有自己的空间。数组名仅仅是一个符号,不是变量,它没有自己的存储空间,而指针实实在在的是个变量,有自己的空间:数组名只是一个符号,不是一个变量,因此不能作为一个左值,因此不能被修改

      只有当数组名在表达式中使用时,编译器才会为它产生一个指针常量。而只有以下两种情况,才不被当做指针常量:

  • sizeof(数组名):返回数组长度(所占的字节数,不是数组元素个数),而不是指向数组的指针的长度。

  • &数组名:产生一个指向数组的指针,而不是一个指向某个指针常量的指针。

二 一维数组


关于一维数组明确一下几点:
1)数组名a是地址常量,他的值为a[0]的地址,所以a+i为a[i]的地址
2)对地址名取地址&a,虽然与a的值相同,但是含义不同,代表的是整个数组的地址。
3)a+1=a+sizeos(int),为a[i]的地址
      &a+1=a+sizeos(a),没有什么实际意义  
4)&a代表的是整个数组的地址。
      &(a+1)是错误的,因为&只能对变量取地址,但是a没有内存空间,a+1不知道赋给了那个变量,而且也没有实际意义
对一维数组取sizeof的问题总结:

要注意的是

1)sizeof(&a)的值是4,因为它的含义是一个指针;

2)变量名一旦进行了移位操作,那么他就退化成了指针所以a+1是指针的含义,所以为4

三 二维数组

在以为数组的基础上理解二维数组
A:数组名的理解
1)首先理解a与&a的区别
 a是二维数组的首地址,在值上等于&a,&a[0][0],*a

但是他们的值虽然相等,但是他们的含义不相同
a代表二维数组的第0行的地址,所以a+1是第1行的地址;
&a代表整个数组的地址,&a+1就把整个数组都越过去了;
*a代表的是第0行第0个的地址,含义相等于一维数组名;

2)a代表的其实是第0行的地址,因此a+i代表的是第i行的地址
     &(a+1)不仅是错误的而且是没有意义的
3)*(a+i)代表的是第i行第0列的地址;跟a[i]的意义一样,相等于数组名
   因此a[i]+1和*(a+i)+1代表的都是第i行第一列的地址
4)与一位数组类似
   a[i]的意义是第i行第0列的地址
& a[i]的意义是第一行这个内部数组的地址
 B:二维数组指针的理解
 attention:理解这些含义的关键在于:那些数组名的形式代表行地址,哪些代表列地址
其实要注意的是:a[0]和*a都是第0行第0列的地址,但是含义是一维数组名,所以对此去&,&a[0]和&(*a)其实相当于对一位数组名取&,转化成了行的地址

对二维数组取sizeof的相关含义:
     

int main99912()  
{      
	int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};     
	int n=sizeof(a[0][0]);        
	printf("a=0x%x,*a=0x%x\n",a,*a);     
	printf("a size=%d,*a size=%d\n",sizeof(a),sizeof(*a));     
	printf("-------------------------------------------\n");
 
	printf("a[0]=0x%x,*(a+0)=0x%x\n",a[0],*(a+0));      
	printf("a[0] size=%d,*(a+0)=%d\n",sizeof(a[0]),sizeof(*(a+0)));
	printf("-------------------------------------------\n");      

	printf("&a[0]=0x%x,&a[0][0]=0x%x\n",&a[0],&a[0][0]);     
	printf("&a[0] size=%d,&a[0][0] size=%d\n",sizeof(&a[0]),sizeof(&a[0][0]));     
	printf("-------------------------------------------\n");     

	printf("a[1]=0x%x,a+1=0x%x\n",a[1],a+1);      
	printf("a[1] size=%d,a+1=%d\n",sizeof(a[1]),sizeof(a+1));   
	printf("-------------------------------------------\n"); 

        printf("&a[1][0]=0x%x,*(a+1)+0=0x%x\n",&a[1][0],*(a+1)+0);     
	printf("&a[1][0] size=%d,*(a+1)+0 size=%d\n",sizeof(&a[1][0]),sizeof(*(a+1)+0));     
	printf("-------------------------------------------\n");     


	printf("a[2]=0x%x,*(a+2)=0x%x\n",a[2],*(a+2));      
	printf("a[2] size=%d,*(a+2) size=%d\n",sizeof(a[2]),sizeof(*(a+2)));     
	printf("--------------------------------------- ---\n");     

	printf("&a[2]=0x%x,a+2=0x%x\n",&a[2],a+2);      
	printf("&a[2] size=%d,a+2 size=%d\n",sizeof(&a[2]),sizeof(a+2))
	printf("-------------------------------------------\n");   

	printf("a[1][0]=0x%x,*(*(a+1)+0)=0x%x\n",a[1][0],*(*(a+1)+0)); 
	printf("a[1][0] size=%d,*(*(a+1)+0) size=%d\n",sizeof(a[1][0]),sizeof(*(*(a+1)+0)));     
	printf("-------------------------------------------\n");    
	return 0;      
}   

解决上面需要注意的问题是:
1 数组名一旦进行移位操作他就退化成了指针
2

printf("a size=%d,*a size=%d\n",sizeof(a),sizeof(*a)); 

这句代码中,sizeof(a)表示整个二维数组的大小,*a表示*(a+0),所以,*a表示一维数组{1,3,5,7}的首地址,因此sizeof(*a)是4*sizeof(int)为16。

printf("a[0] size=%d,*(a+0)=%d\n",sizeof(a[0]),sizeof(*(a+0))); 

a[0]也就是*(a+0),和*a一样,也是指向一维数组{1,3,5,7}的首地址,因此a[0],*(a+0)用sizeof计算内存大小,是4*sizeof(int)为16 

printf("&a[0] size=%d,&a[0][0] size=%d\n",sizeof(&a[0]),sizeof(&a[0][0])); 

&a[0]就是&(*(a+0)),&和*互相抵消,因此相当于a+0,数组名参与了指针偏移运算,因此sizeof(&a[0])的大小为指针的内存小,是4字节。&a[0][0]就是&(*(*(a+0)+0)),&和*抵消以后,为*(a+0)+0,*(a+0)代表一维数组{1,3,5,7}的首地址,因此*(a+0)+0表示数组首地址参与偏移操作,成为指向数组{1,3,5,7}0号位元素1的指针,sizeof(&a[0][0])的大小为4字节。


四 字符串数组

1 一维数组对应的字符串
注意字符串带来的新特性:输出字符串的首地址,会输出整个字符串, 所以效果如上图所示
1)为什么输出字符串的首地址,会输出整个字符串
无论是char*p="hello word"还是字符数组char p[]="12345",p均表示的是字符串的首地址,而cout<<p得到的都是整个字符串,C/C++规定当输出的字符串首地址时会输出整个字符串,直到遇到‘\0’.
所以需要注意的是当我们做一些面试题目的时候,处理字符串时,一定不要忘了字符串以‘\0’结尾的重要性
2)
[cpp]  view plain  copy
  1. #include "stdio.h"  
  2. char *get_string_1()  
  3. {  
  4.     char p[] = "hello world!";  
  5.     return p;  
  6. }  
  7. char *get_string_2()  
  8. {  
  9.     char *p = "hello world!";  
  10.     return p;  
  11. }  
  12. int main()  
  13. {  
  14.     char *p;  
  15.     p = get_string_1();  
  16.     printf("get_string_1:%s/n",p);  
  17.     p = get_string_2();  
  18.     printf("get_string_2:%s/n",p);  
  19.     return 0;  
  20. }  

输出:
get_string_1:(乱码或者没有输出,linux下没有任何输出)
get_string_2:hello world!
3)
char*p[ ]={"hello", word};
p是一个一维数组,内容是char类型的指针,因此不能通过p来改变内容,例如p[0][0]='r';


A: cout<<p——输出的是地址
B: cout<<*p——输出的是第一个字符串。*p相当于char*p中的p
C:: cout<<**p——输出的是第一个字符串的第一个字符
2)p+1.p+2也是地址相当于第1个和第二个字符串的地址。
A: cout<<*(p+1)——输出的word
B: cout<<**(p+1)——输出的w
C: cout<<(*(p+1)+1)——输出的ord
D: cout<<*(*(p+1)+1)——输出的o
3)*p+1相当于 char*p中的p中的p+1,指向了第一个字符串的第二个字符开始的字符串。
A: cout<<*p+1——输出的ello
B: cout<<*(*p+1)——输出的e
 2 二维数组对应的字符串
 
注意:在输出字符串时,当指针指向的是字符串的第一个字符的时候才会输出字符串,而所以上面当p+1表示第一行的地址,输出的是地址,不是字符串,只有*(p+1)代表p[1]代表第一行第0个字符地址,输出整个字符串

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值