只要是程序员,相信使用数组已经是家常便饭了,但是您真的懂吗? 未必...
本文章为原创,转载请注明出处,谢谢.
作者 : 飞哥
1. 实数数组的初始化
1.1 一维数组初始化
方式1 :
例1:
int arr[10] = {0,0,0,0,0,0,0,0,0,0};
该种初始化完全可以用以下方式代替
int arr[10] = {0};
例2:
int arr[10] = {1,2,3,4,5};
该种方式只对前五个数据赋值,那后五个数据是多少呢?
答案: 在{}方式下,未初始化的元素一律初始化为适当类型的0;
方式2 :
例如:
int arr1[] = {1,2,3,4,5,6,7,8,9,10}; //ok
int arr2[] = {1,2,3,4,5}; //ok
释义: 如果不明确定义数组的长度,则根据初始化表的长度确定数组的长度。
拓展1 : 如果数组没有初始化,那么将其值输出会是多少? 0还是不确定数字?
答案 : 为不确定的数字;
int arr[10];
for(int i = 0; i < 10; i++) printf("%d",arr[i]); //输出的都是不确定的数字
请对比方式1中的例2,以免混淆;
拓展2 : 可以在代码中直接声明空数组吗?
例如: int arr[]; //error,目前还不支持;
深入1:
int a[10];
printf ("%d\n", sizeof (a));
printf ("%d\n", sizeof (a));
输出为 : 40 //较简单不再赘述;
void test(int szData[])
{
printf("%d",sizeof(szData));
}
int szData[10];
test(szData); //输出为4,为什么?
答案: 函数调用过程中,形参与实参结合的过程实际上就是一个赋值的过程.
函数调用数组类型的参数时,形参得到的是实参数组的首地址,即:只是
将实参数组首地址赋值给形参。所以形参实际上只是一个普通指针,编译器
只知道其是个指针不知道其是否是数组形式的;
深入2 : int szData[10];
printf ("%p\n", szData);
printf ("%p\n", &szData[0]);
printf ("%p\n", &szData);
printf ("%p\n", &szData[0]);
printf ("%p\n", &szData);
请问以上三个输出的地址相同吗?
第一个和第二个相同很好理解;关键是为什么第三个也和上面两个值相同呢?
因为 :printf ("%p\n", szData); 中szData代表的是数组首地址;
而 printf ("%p\n", &szData); 中szData代表的是整个数组,也就是说输出的是整个数组的首地址;
所以,一定要分清什么时候是代表整个数据,什么时候是代表数组首地址;
1.2 二维数组初始化
1.2.1)概念巧解
很多教科书上对二维数组的概念总是这样描述:
二维数组是由多个一维数组组成的数组;
这样的描述实在是糟糕透了,对于初学习的人来说在这句话上就得很大的劲去想象理解;
为了简单理解其概念,我这样解释:
二维数组 : 把一个一维数组分组后就变为二维数组,本质还是一维数组;
例如:
int arr[6] = {2,3,5,6,8,3};
也可以用二维数组存放该组数据:
int arr[2][3] = { {2,3,5},{6,8,3}};
即 :
int arr[2][3] = {2,3,5,6,8,3} ;
分组实际上就是把一个一维数组又分成了多个一维数组而已;
再进一步 : 把一维数组转为二维数组
例如:
int szData[10] = {8,3,5,6,2,9};
int szMyData[][2] = &szData;等价于 : int (*szMyData)[2] = &szData
arr : 类似一维数组,什么时候代表整个数组,什么时候代表的是数组首地址一定要分清;
arr[i] : 代表第i组的一维数组;
arr[i][j] : 代表第i组的一维数组的第j个数据;
1.2.2)二维数组初始化
上面的概念中所讲例子属于一种初始化方式,接下来用举例的方式讲解其他方式:
例如1:
int arr[][3] =
{2,3,5,6,8,3} ;// ok
int arr[][] = {2,3,5,6,8,3}; //error
为什么?
答案:
我们知道一维数组时初始可以写为: int arr[] = {2,3,5,6,8,3};
编译器可以通过数组中有多少个数来确定分配空间的大小;
但是对于二维数组:
重点1:
未指定分组个数,只指定每组个数n :
编译器会自动把每个组分为n个数,如果个数不足,则自动填充为0;
例如: int arr[][4] = {2,3,5,6,8,3} 等价于 int arr[][4] = {{2,3,5,6},{8,3,0,0}};
即: sizeof(arr) 值为 8 * 4 = 32;
既未指定分组个数,也未指定每组个数n :
编译器一头雾水,不知道该怎么为你的数组分组了,所以直接报错;
例如2 : int arr[][3] = {{1},{3,5},{1,6,8}};//ok
为什么?
释义: 二维数组概念中我说其就是将一维数组分成多个一维数组,
二维数组支持 int arr[3] = {1};或者 int arr[3] = {3,5}这样的初始化方式
所以上面二维数组的写法没有错误;
1.2.3) 二维数组作为参数传入函数
为节省篇幅,举例说明:
方式1 :
例如:
void test(int szData[][4], int size)
{
int i;
for (i = 0; i < size; i++)
{
int j;
for (j = 0; j < sizeof (szData[0]) / sizeof (szData[0][0]); j++) //第1个数组大小除以一个数据大小为数组个数4
printf ("%4d", szData[i][j]);
}
}
方式2 : 例如:
void test(int* szData,int nDataCount)
{
int* pData = szData;
for (int i = 0; i < nDataCount; i++)
{
printf("%d ",szData[i]);
}
}
int szData[3][3] = {{1},{4,6,7},{8,3}};
test((int*)szData,9); //输出为: 100 467 830 </span>
释义: 二维数组本质是一维数组。 是不是有点一语点破醍醐灌顶的感觉呢?
2.字符数组
2.1)一维字符数组初始化
例如: char szUser[] = "飞哥在此";
等价于:
char szUser[] = {'飞','哥','在','此','\0'};
所以: sizeof(szUser) 值为9;
2.2)表示字符串的三种方式:
1)字面值方式:"hello"
2)字符数组方式:char arr[10] = {'h', 'e', 'l', '\0'};
3)字符指针方式:char* szData;
区别:
1)字面值存储在程序的静态存储区(全局区),其值不可改变。值相同的字面值内存地址一样。
2)字符数组在内存堆栈区,其值可以改变,但数组本身的地址是一个常量不可被改变。
3)字符指针存储的是一个地址,既可以指向字面值,也可以指向字符数组,对于前者字符的内容不能修改,而对于后者则可以修改。
3)字符指针方式:char* szData;
区别:
1)字面值存储在程序的静态存储区(全局区),其值不可改变。值相同的字面值内存地址一样。
2)字符数组在内存堆栈区,其值可以改变,但数组本身的地址是一个常量不可被改变。
3)字符指针存储的是一个地址,既可以指向字面值,也可以指向字符数组,对于前者字符的内容不能修改,而对于后者则可以修改。
例1:
char* pName = "飞哥在此";
pName[0] = "王"; //error!段错误或者程序崩溃
为什么?
释义: pName指向的是一串字符串,该字符串以字面值存在于静态存储区,是定死的,不可以被改变;
例2:
char szData1[10];
char szData2[10];
szData1 = szData2;//error
char szData2[10];
szData1 = szData2;//error
为什么?
释义: 数组本身的地址是指针常量,不可以被改变;
2.2)二维字符数组初始化
方式1 : char szName[2][64] = {"飞哥","小刘"};
方式2: char* szName[] = {"飞哥","小刘"};
3.使用数组注意点
3.1)数组名不能与其它变量名相同
例如:
void main()
{
int a;
float a[10];//error
……
}
3.2)不能用变量表示元素的个数, 但是可以是常数或常量表达式 例如:
<pre name="code" class="cpp">void main()
{
int n=10;
int szData[n]; //error
}
3.3)指针数组与数组指针区别?
数组指针 : 存放数组的指针; 例如 :char (*pData)[5]; //pData就是存放数组的指针;
例如:
int szData[][5] = {1,3,6,8,3,5,9};
int (*pData)[5];
pData = szData;
指针数组 : 存放指针的数组; 例如: char* pData[64]; //pData就是存放指针的数组;
例如:
int n1 = 1,n2 = 3,n3 = 5;
int *p[10] = {&n1,&n2,&n3};
4.数组面试题
下面题目有问题吗?如果有问题怎么修改?
char *strA()
{ char str[]
= “Hello World”; return str; } |
str[]数组是函数strA()的局部变量,当调用完这个函数后,局部变量str被销毁,所以返回的结果是不确定的。
修改如下:
修改如下:
const char *
strA() { char *str
= “Hello World”; return str; } |
”Hello
World”是字符串常量,它位于静态存储区,其在程序内部内存位置是不会被改变的;