数组深入理解

一.数组名
数组就是一段连续可用的内存。
比如声明一个 int数组
int array[]={1,2,3};
array代表什么?有的资料说:数组名是指向数组首地址的常量指针。
下面我们可以验证一下。
我们知道sizeof操作符可以返回一个对象或者类型所占的内存字节数。
如:
int i=1;
那么sizeof(i) 的结果就是4
那我们打印sizeof(array)
printf("%d\n",sizeof(array));
结果是:12。
但是我们都知道sizeof(指针变量)==4的。
所以我们得出:数组名不完全是指向数组首地址的常量指针。
为什么要用不完全,因为我们利用数组来访问数组元素的时候。它又变得像一个常量指针。
比如
array[0]等效于
(array+0)
时候 array就是一个指向数组首地址的常量指针,指针类型是指向数组元素类型的指针。这里就是 int类型
我们可以这样理解:
一个大学的名字叫array。
有人问你array是什么。你会告诉他array是大学,面积多少之类的。
但是有人问你去array怎么走,你会告诉他array的校门(首地址)在哪里。
结论:数组名其实代表的是一个内存区域,但是使用的时候变成了 指向数组首地址的常量指针。
但是这里还有一个小陷阱:

#include <stdio.h>
void foo(int a[])
{
  printf("%d\n",sizeof(a));
}
int main(void)
{
  int array[]={1,2,3};
foo(array);
return 0;
}
出的不是12,而是4。
出于效率的考虑,数组传参是引用传参而不是拷贝传参。因为数组长度可能很大,拷贝一份的话太耗资源。
虽然我是这样函数是这样的

void foo(int a[])
{
printf("%d\n",sizeof(a));
}
编译器的眼中是这样
void foo(int a)
{
printf("%d\n",sizeof(a));
}
所以sizeof(a)是sizeof(指针变量)肯定是4。
*
二 .字符数组
*首先我们看一个简单的程序
#include <stdio.h>
int main(void)
{
  char str1=“abc”;
  char str2[]=“def”;
  printf("%s\n",str1+4);
  return 0;
}
输出的结果是 def。
我们要知道c语言中只要用到了 “xxxxx”,系统都会自动的把双引号的内容添加到字符常量区。
注意:printf(“xxxx”);不会把"xxxx"添加到字符常量区。
char str1=“abc”; //会把 abc\0 添加到字符常量区,并把首地址赋值给str指针变量。
char str2[]=“def”; //会把 def\0 添加到字符常量区,并且函数栈中添加一个字符数组 内容也是 def\0,str2指向的是栈中的数组。
char str[]={‘x’,‘y’,‘z’}; //只会在函数栈中添加数组
由于字符常量区是连续的,所以
printf("%s\n",str1+4);
可以打印出str2的值。

三. 二维数组
i
nt array[][3]={1,2,3,4,5,6};
前面我们已经说了,使用array访问元素时,array就是一个指针类型为指向数组元素的指针类型,指向数组首地址的指针。
二维数组的元素就是数组,
这样写就更容易理解:

int array[][3]={{1,2,3},{4,5,6}};
*所有可以 这样认为
int (const array)[3];

**当我访问数组元素时候
array[x][y]在编译器看来就是 ((array+x)+y)
(array+x) 得到的是一个 第x行 类型为 “int[3]”(c语言没有这样的写法) 的数组,
数组名在访问元素的时候当做首地址指针来用,在这里 (array+x)等同于数组名,
指针类型int ,指向的地址为 array+sizeof(int()[3])x。
访问这个数组的第y个元素的时候,就要用 ((array+x)+y)。

四.字符数组与字符串
在c语言中,将字符串作为字符数组来处理。(c++中不是)
在实际应用中人们关心的是有效字符串的长度而不是字符数组的长度,例如,定义一个字符数组长度为100,而实际有效字符只有40个,为了测定字符串的实际长度,C语言规定了一个“字符串结束标志”,以字符’\0’代表。如果有一个字符串,其中第10个字符为’\0’,则此字符串的有效字符为9个。也就是说,在遇到第一个字符’\0’时,表示字符串结束,由它前面的字符组成字符串。
系统对字符串常量也自动加一个’\0’作为结束符。例如"C Program”共有9个字符,但在内存中占10个字节,最后一个字节’\0’是系统自动加上的。(通过sizeof()函数可验证)
有了结束标志’\0’后,字符数组的长度就显得不那么重要了,在程序中往往依靠检测’\0’的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串长度。当然,在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串实际长度。(在实际字符串定义中,常常并不指定数组长度,如char str[ ])
说明:’\n’代表ASCII码为0的字符,从ASCII码表中可以查到ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不干。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。
对C语言处理字符串的方法由以上的了解后,再对字符数组初始化的方法补充一种方法——即可以用字符串常量来初始化字符数组:
char str[ ]={“I am happy”}; 可以省略花括号,如下所示
char str[ ]=“I am happy”;
注意:上述这种字符数组的整体赋值只能在字符数组初始化时使用,不能用于字符数组的赋值,字符数组的赋值只能对其元素一一赋值,下面的赋值方法是错误的
char str[ ];
str=“I am happy”;
不是用单个字符作为初值,而是用一个字符串(注意:字符串的两端是用双引号“”而不是单引号‘‘括起来的)作为初值。显然,这种方法更直观方便。(注意:数组str的长度不是10,而是11,这点请务必记住,因为字符串常量"I am happy"的最后由系统自动加上一个’\0’)
因此,上面的初始化与下面的初始化等价
char str[ ]={‘I’,’ ‘,‘a’,‘m’,’ ‘,‘h’,‘a’,‘p’,‘p’,‘y’,’\0’};
而不与下面的等价
char str[ ]={‘I’,’ ‘,‘a’,‘m’,’ ‘,‘h’,‘a’,‘p’,‘p’,‘y’};
前者的长度是11,后者的长度是10.
说明:字符数组并不要求它的最后一个字符为’\0’,甚至可以不包含’\0’,向下面这样写是完全合法的。
char str[5]={‘C’,‘h’,‘i’,‘n’,‘a’};
++++++++
可见,用两种不同方法初始化字符数组后得到的数组长度是不同的。

#include <stdio.h>
void main(void)
{
char c1[]={‘I’,’ ‘,‘a’,‘m’,’ ',‘h’,‘a’,‘p’,‘p’,‘y’};
char c2[]=“I am happy”;
int i1=sizeof(c1);
int i2=sizeof(c2);
printf("%d\n",i1);
printf("%d\n",i2);
}
结果:10 11

猜你喜欢

转载自blog.csdn.net/qq_43638758/article/details/84349623