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;
}

运行结果如下图:

image

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的动作是向后偏移整个数组的大小。
运行结果如下图:
image

第二种情况:当 数组名 和 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;
}

运行结果如下图:
image

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;
}

运行结果:
image

可以调用库函数 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;
}

运行结果:image

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;
}

运行结果:image

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;
}

运行结果:
image

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;
}

运行结果:
image

#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;
}

运行结果:

image

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;
}

运行结果:

image

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.指针数组 在指针部分介绍

posted @ 2026-08-01 15:45  !城北徐公.!  阅读(16)  评论(0)    收藏  举报