2026/08/01 C语言的数组
一、C语言的数组
数组的概念
数组就是相同类型数据的集合,简单的说数组就是由n个数据组合在一起。其实就是用户向内核申请的一块空间,只不过内核提供的这块空间的内存地址是连续的,目的就是方便用户存储数据和访问数据。
如果申请成功则操作系统会把内存的起始地址提供给用户,用户可以通过存储单元的地址访问,但是程序的可读性以及可维护性变差,所以C语言允许用户像访问变量一样,可以对数组进行命名,这样系统内核就会把数组名和数组的起始地址建立映射关系。
用户需要说明 数据数量 * 数据宽度 ,对于数据宽度而言指的是数据类型 ,数据的类型可以是基本数据类型(字符型、整型、短整型、浮点型) or 复杂数据类型(结构体、联合体) or 指针类型
1.数组的定义
定义数组的格式: 数据类型 数组名称 [数据个数] ; // 内存大小:数据类型 * 数据个数
数组声明符[]内部需要有一个表达式,用于指定数组的大小,表达式的值应该是整形。
2.数组的访问
E1[E2]=(*(E1+E2))
E1[E2]表示数组对象E1中的第E2个元素(E2的范围是0~(E2-1))
数组名在C语言标准中是指向数组第一个元素的地址。
*(E1+E2)的解释:E1是一个数组对象,E1也就是数组名称,C语言标准中规定数组名可以作为数组中第一个元素的地址,所以相当于E1是数组中第一个元素的地址,而E2是一个整数,所以 E1 + E2 相当于从E1这个地址向后偏移E2个单位(以元素为单位,所以需要考虑元素的类型),所以E1+E2的结果还是一个地址, *( E1 + E2) 相当于间接访问该地址,相当于得到了(E1+E2)这个地址下的值。
E1[E2]->(E1+E2)->(E2+E1)->E2[E1]
所以buf[0] = 'h'和 0[buf] = 'h'的作用相等,可以等价。
#include <stdio.h>
int main(int argc, char const *argv[])
{
char buf[11];
buf[0] = 'H';
buf[1] = 'e';
buf[2] = 'l';
buf[3] = 'l';
buf[4] = 'o';
5[buf] = 'w';
6[buf] = 'o';
7[buf] = 'r';
8[buf] = 'l';
9[buf] = 'd';
10[buf] = '\0';
printf("%s\n", buf);
printf("%c\n", buf[1]);
printf("%c\n", *(buf + 1));
return 0;
}
运行结果如下图:

C语言标准中提到数组名可以用于表示数组的第一个元素的地址,但是此时有两种例外情况。
第一种情况: 当 数组名 和 &地址运算符 一起使用时,数组名就不表示数组首元素的地址,而表示数组本身。
#include <stdio.h>
int main(int argc, char const *argv[])
{
int buf[5];
printf("%p\n",buf); //输出数组首元素的地址
printf("%p\n",buf+1); //输出数组首元素的地址向后偏移四个字节 = 输出数组第二个元素的地址
printf("%p\n",&buf+1); //与&单独使用,向后偏移一个数组的大小,即向后偏移20个字节
return 0;
}
(&buf+1) 可以知道 &取地址符和数组名一起使用时,数组名不表示数组第一个元素的地址,而表示数组本身的地址,所以+1的动作是向后偏移整个数组的大小。
运行结果如下图:

第二种情况:当 数组名 和 sizeof()运算符 单独使用的时候,数组名就不表示数组首元素地址,而表示数组本身。
#include <stdio.h>
int main(int argc, char const *argv[])
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(arr)); //输出数组的大小
printf("%d\n",sizeof(arr+0)); //输出指针的大小
printf("%d\n",sizeof(*arr)); //输出数组中元素的大小
printf("%d\n",sizeof(arr[1])); //输出数组中元素的大小
printf("%d\n",sizeof(&arr)); //输出指针的大小
printf("%d\n",sizeof(&arr+1)); //输出指针的大小
printf("%d\n",sizeof(&arr[0]+1)); //输出指针的大小
return 0;
}
运行结果如下图:

3.数组的初始化
C语言标准中规定数组可以进行初始化,注意:只有定义数组的同时进行赋值才叫初始化!
格式:数据类型 数组名[数组容量] = {0}; 比如 int buf[5] = {0,0,0,0,0}; //数组初始化
int buf[5] = {1}; 等价于 int buf[5] = {1,0,0,0,0};
int buf[ ] = {0};是符合语法的,可以在定义数组时不指定数组的元素个数,但是此时需要在定义数组的同时初始化数组,系统会自动计算元素个数。
可以利用sizeof()运算符来计算数组的容量,计算出的数组大小是以字节为单位,然后再用数组容量 / 数组中元素的类型就可以得到数组中元素的个数。
#include <stdio.h>
int main(int argc, char const *argv[])
{
int buf[] = {1,2,3,4,5};
printf("buf size: %d bytes\n",sizeof(buf));
printf("buf element number: %d\n",sizeof(buf)/sizeof(buf[0]));
return 0;
}
运行结果:

可以调用库函数 bzero() 以及 memset() ,可以专门对数组进行处理,尤其是清空数组的处理。memset() 比 bzero() 更灵活。
bzero() 包含于 strings.h 头文件中
#include <stdio.h>
#include <strings.h>
int main(int argc, char const *argv[])
{
int buf[10] = {0,1,2,3,4,5,6,7,8,9};
bzero(buf, 5 * sizeof(int)); //将buf数组的前5个元素清零
for (int i = 0; i < 10; i++)
{
printf("%d ", buf[i]);
}
printf("\n");
return 0;
}
运行结果:
memset() 按字节中填充指定数据 包含于 string.h 头文件中
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int buf[10] = {0,1,2,3,4,5,6,7,8,9};
memset(buf, 0, sizeof(buf)); //把buf数组的前sizeof(buf)个字节的内容全部设置为0
for (int i = 0; i < 10; i++)
{
printf("%d ",buf[i]);
}
printf("\n");
return 0;
}
运行结果:
memset(buf, 0, sizeof(buf)) 等价于 bzero(buf, sizeof(buf))
4.字符型数组
一般实际开发中,使用数组一般都是为了存储字符序列,C语言中的字符串也属于字符序列,字符串需要使用双引号””进行限制,双引号””表示字符串的首字符的地址,字符串的结束以’\0’作为结束。
#include <stdio.h>
int main(int argc, char const *argv[])
{
char arr[] = "abcdef";
printf("%p\n",arr); //输出数组的首地址址
printf("%d\n",sizeof(arr)); //输出数组的大小:6个字符+1个'\0' = 7
printf("%d\n",sizeof(arr+0)); //输出指针的大小
printf("%d\n",sizeof(*arr)); //输出数组中元素的大小
printf("%d\n",sizeof(arr[1])); //输出数组中元素的大小
printf("%d\n",sizeof(&arr)); //输出指针的大小
printf("%d\n",sizeof(&arr+1)); //输出指针的大小
printf("%d\n",sizeof(&arr[0]+1)); //输出指针的大小
return 0;
}
运行结果:

5.数组型数组(多维数组)
维度是针对用户而言,内存是线性的,是不分行和列的,所以多维数组其实和一维数组的本质是一样的,都是为了申请一块连续的内存空间,并且内存空间存储的数据的类型是一致的
二维数组定义格式 : 元素类型 数组名称[元素数量][元素数量] 比如 int buf[2][3] = {0};
多维数组可以通过下标的方式或者地址的方式进行访问
下标的方式: 直接访问buf[3][4];
通过地址的方式访问buf[3][4]:则如果打算访问 buf[1][1] ==> * ( ( *(buf + 3) ) + 4 ) ;
#include <stdio.h>
int main(int argc, char const *argv[])
{
int buf[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
printf("buf[1][2] = %d\n",buf[1][2]);
printf("buf[1][2] = %d\n",*(*(buf+1)+2));
return 0;
}
运行结果:

#include <stdio.h>
int main(int argc, char const *argv[])
{
int a[3][4] = {0};
printf("%d\n",sizeof(a)); //数组a占用的内存空间大小:3*4*sizeof(int) = 48
printf("%d\n",sizeof(a[0][0])); //数组a中每个元素的大小:sizeof(int) = 4
printf("%d\n",sizeof(a[0])); //数组a中每行的大小:4*sizeof(int) = 16
printf("%d\n",sizeof(a[0]+1)); //指针的大小:8
printf("%d\n",sizeof(*(a[0]+1))); //指向数组a中第一行的第二个元素的大小:sizeof(int) = 4
printf("%d\n",sizeof(a+1)); //指针的大小:8
printf("%d\n",sizeof(*(a+1))); //指向数组a中第二行的大小:4*sizeof(int) = 16
printf("%d\n",sizeof(&a[0]+1)); //指针的大小:8
printf("%d\n",sizeof(*(&a[0]+1))); //指向数组a中第二行的大小:4*sizeof(int) = 16
printf("%d\n",sizeof(*a)); //指向数组a中第一行的大小:4*sizeof(int) = 16 *a等价于*(a+0)等价于 a[0]
printf("%d\n",sizeof(a[3])); //指向数组a中第四行的大小:4*sizeof(int) = 16 a[3]等价于*(a+3)
return 0;
}
运行结果:

6.柔性数组
柔性数组也被称为变长数组,但是注意:当数组的内存一旦确定,则不会因为变量发生变化导致数组长度变化!
#include <stdio.h>
int main(int argc, char const *argv[])
{
int cnt = 0;
printf("please input cnt value:\n");
scanf("%d", &cnt);
int buf[cnt]; //柔性数组
printf("buf size: %d\n", sizeof(buf)); //柔性数组的大小是根据cnt的值来确定的
return 0;
}
运行结果:

7.匿名数组
一般都是在函数参数中或者在多维数组中使用,很少单独使用。
比如二维数组 int buf[3][4]; ---> buf[3] 数组的每个元素的类型是 int [4] ,就是匿名数组。
8.零长度数组
数组的长度可以是0,但是由于数组长度是0,所以操作系统是不会提供内存单元给数组的!但是用户是可以访问的。
一般都是结合C语言的结构体一起使用,可以用于对结构体进行拓展,所以零长度数组也属于柔性数组的一种。
struct demo
{
int a;
int b;
int c[6];
long long d;
char e;
char buf[0]; //零长度数组,可以利用该数组去访问结构体中的其他成员变量。
};
9.指针数组 在指针部分介绍
作者:bbzhu04@gmail.com ,多有不妥之处,望批评指正
本文原创,欢迎转载;转载请在文章显著位置标明原文链接: href="https://www.cnblogs.com/zhubb/p/22132349"
保留所有权限,未经许可禁止篡改、商用发布。

浙公网安备 33010602011771号