Summary
1)数组是相同数据类型变量
的有序集合
2)如果未给定数组元素大小,编译器会根据数组元素的个数自动推断数组的大小;数组中后面未被初始化的元素会被自动初始化为0。
3)数组的本质是一段连续的内存
,用于存储数组元素;数组的大小
可以通过sizeof获取,单位:字节;sizeof(arrName)
。数组的元素个数:sizeof(arrName) / sizeof(arrName[0])
4)数组的类型由元素类型
和元素个数
决定,表示为type [N]
5)多维数组的本质仍然是一维数组
,数组里的每一个元素是数组
6)字符串的本质是一个字符数组
7)C语言中对字符串或者字符数组的操作,一定要关注0元素('\0'结束符)
;如果使用字符数组来模拟字符串变量,一定记得在最后一个元素后加上结束符'\0'
8)字符串字面量的长度strLen
:结束符'\0'之前的所有字符
;字符串字面量占用的内存大小strSize
:包括'\0'的所有字符
。即strSize = strLen + 1
;
9)char *strcpy(char *dst, const char *src)
;注意strcpy的第二个参数必须是一个字符串
1、一维数组
1.1 数组的概念
数组是相同数据类型
变量的有序集合
。
- 数组作为整体需要一个合法的命名(
数组名
) - 数组中的
变量
没有独立命名,只有在数组中的编号 - 数组中的变量数量是固定不变的(
数组大小固定
)
1.2 数组的定义
语法:type Name[size];
int arr[10]; // 定义名为arr的数组
// 数组中一共有10个元素(变量)
// 每个元素的类型为int
1.3 数组的访问
- 通过
数组名[下标]
的方式访问数组 - 数组是一个有序的集合,每个元素都有固定的下标
- 数组元素下标固定从0开始(可以使用变量作为下标)
int arr1[3];
arr1[-1] = 0; // error,数组下标从0开始
arr1[0] = 1; // ok
arr1[3] = 4; // error,数组中一共有3个元素,最后一个元素下标为2,下标3越界了
注意:
- 只有
整型数
才能作为下标来访问数组元素 下标越界
是非常严重的错误- 下标越界造成的
严重后果
可能不会立刻体现出来
1.4 数组的初始化
语法:type Name[N] = {v0, v1, ..., vN-1};
意义:将数组中的元素分别初始化为v0, v1, ...
int main()
{
int arr[5] = {2, 4, 6, 8, 10}; // 定义数组arr并初始化
int i = 0;
for(i=0; i<5; i++)
{
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
数组初始化技巧:
- 自动确定数组大小
type Name[] = {v0, v1, ....}; // 编译器会根据初始值的个数自动确认数组的大小 - 将部分数组元素初始化为0
/ S<N,未指定初始值的元素默认为0
type Name[N] = {v0, v1, ..., vS}; // 前面的元素给了初始值,后面没给的都是0 - 将所有数组元素初始化为0
type Name[N] ={0}
; // 同上一点,第一个元素给了0,后面每给的都是0
1.5 数组的内存分布
数组再计算机底层是一片连续的内存
,用于存储数组元素
type Name[n] = {v0, v1, ....};
数组的大小:sizeof(Name)
数组的元素个数:sizeof(Name) / sizeof(Name[0])
- 数组名是一个
右值
,可以看做一个常量指针
- 只能用
整形常量
对数组进行定义,因为要在编译期分配内存 - 只能用
整形值
作为下标来访问数组元素
1.6 数组的类型
- 数组类型由
元素类型
和数组大小
共同决定 - 数组类型的具体表现形式为
type [N]
int a[10] = {0}; // arrType: int [10]
float b[5] = {0}; // arrType: float [5]
int c[10]; // arrType: int [10]
int i = 0;
for(i=0; i<10; i++)
c[i] = a[i]; // 相同类型数组的“赋值操作”
2、二维数组和多维数组
2.1 二维数组
数组中的元素可以是变量,也可以是其他数组元素(如数组、指针、函数等),当数组中的元素是另一个数组时,就构成了多维数组。
C语言中的二维数组定义:type Name[N1][N2]
;二维数组可以看做数学中的矩阵(N1行N2列的矩阵)。
注意:二维数组的本质仍然是一维数组
,即:数组中的每一个元素是数组
int a[3][4]; // 定义一个数组,里面有3个元素
// 每个元素的类型是 int [4]
(a[1])[2] = 2; // 对第1个数组中的第2个变量赋值
a[2][3] = 2; // 对第2个数组中的第3个变量赋值
a[3][0] = 0; // error, index out of bound
二维数组的初始化:
// 1 2 0
// 4 5 0
int a[2][3] = {{1, 2}, {4, 5}};
// 1 2 3
// 4 0 0
int a[2][3] = {1, 2, 3, 4};
// 0 0 0
// 0 0 0
int a[2][3] = {0};
// 1 2 3
// 4 5 6
int a[][3] = {{1, 2 ,3}, {4, 5, 6}};
// 1 2 3
// 4
int a[][3] = {1, 2, 3, 4}; // {{1, 2, 3}, {4}}
注意:
- 二维数组能且仅能让编译器自动确定第一维的大小
第二维大小必须显示给定
,即:数组元素的类型必须正确合法
一个一维数组的类型为:type [size],一维数组的size编译器可以推断,但type必须确定。对于二维数组type [size1][size2]
,大小为size1,可以推断,但type必须明确,即type [size2]是必须明确的,所以第二维大小必须确定。第一维大小自动确定的方法:(初始值个数
除以
第二维大小)向上取整
int a[][3] = {1, 2, 3, 4}; int s1 = sizeof(a) / sizeof(a[0]); // s1 = 2 int i = 0; int j = 0; for(i=0; i<s1; i++) { for(j=0; j<3; j++) { printf("a[%d][%d] = %d\n", i, j, a[i][j]); } }
练习题:输出矩阵的转置
int a[3][3] = {1, 2, 3, 4};
int i = 0;
int j = 0;
int arr[3][3] = {0};
// 转置
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
if(i == j)
arr[i][j] = a[i][j]; // 对角线上的值不变
else
{
arr[j][i] = a[i][j]; // 其余位置变换
}
}
}
2.2 多维数组
三维数组定义:一个数组,每个元素为一个二维数组
- 语法:
type name[n1][n2][n3];
四维数组定义:一个数组,每个元素为一个三维数组
- 语法:
type name[n1][n2][n3][n4];
后续以此类推。
3、字符串和字符数组
3.1 字符数组
字符数组是特殊的整数
的有序集合
(字符的有序集合),字符数组里的每个元素都是char类型的变量,可视化的字符
- 每个整数占用1字节(-128 - 127)
- 可以用
字符字面量
对数组元素进行初始化和赋值 - 常用来存储可阅读的文本信息
char a[] = {97, 98, 99}; // 使用整数初始化字符数组
char b[] = {'d', '.', 't', '.'}; // 使用字符字面量初始化字符数组
int i = 0;
for(i=0; i<sizeof(a); i++)
printf("%c ", a[i]); // a b c
printf("\n");
for(i=0; i<sizeof(b); i++)
printf("%c ", b[i]); // d . t .
3.2 字符串
字符串的定义:双引号括起来的有序字符集,如"hello"
C语言中:
没有
专用的字符串类型- 只能通过
字符数组
来模拟字符串变量 - 存在
字符串字面量
,但仅能作为常量
使用
因此:
字符串变量
:使用字符数组来模拟字符串常量
:双引号括起来的有序字符集
字符串中的0元素:
整数0
即字符串中的0元素
0元素对应的字符为'\0'
(转义字符),转义指的是使用反斜杠'\'转变原来的字符意义,'0'字符原来对应的十进制整数值为48,经过转义后,'\0'表示十进制整数0'0'与'\0'不同,
字符'0'是一个非0值,对应十进制整数48
printf("%d\n", '0'); // 48 printf("%d\n", '\0'); // 0
3.2.1 “字符串变量”:字符数组
- C语言中通过字符数组来
模拟
字符串变量 当字符数组中存在0元素时,可当做字符串
来使用- 字符数组中的'\0'表示一个字符串的结束
字符数组中的元素,不一定是字符串中的元素
char ss[] = {'c', 'c', '\0', 'j'}; // ss表示的字符串为"cc",字符'j'在字符数组ss中, // 但并不是字符串中的内容
- 字符数组
可以用字符串常量进行初始化
- 一个字符数组
不一定
是一个字符串(看是否包含0元素'\0'
); 一个字符串
一定
是一个字符数组char dt[] = "abcd"; char name[] = {"efg"}; // 加不加{}都是等价的 int ds = sizeof(dt); // 5 int ns = sizeof(name); // 4 printf("dt = %s\n", dt); // abcd printf("ds = %d\n", ds); // 5 printf("name = %s\n", name); // efg printf("ns = %d\n", ns); // 4
3.2.2 字符串操作
C语言中的“字符串变量”不存在运算操作!
但存在一个字符串“工具包”string.h,提供了一些字符串操作工具,这些工具的本质就是与字符串相关的运算操作。
- strlen(s) -> 获取字符串的
长度
- strcpt(s1, s2) -> 将s2中的字符复制到s1,
s1 = s2
- strcat(s1, s2) -> 将s2追加到s1后面,
s1 = s1 + s2
strcmp(s1, s2) -> 比较s1和s2是否相等,
相等时为0
#include <stdio.h> // 声明工具包,要使用里面的输出工具 #include <string.h> // 声明工具包,要使用里面的字符串相关工具 int main() { char s[10] = "abcd"; int size = sizeof(s); int len = strlen(s); printf("size = %d\n", size); // 10 printf("len = %d\n", len); // 4 char in[16] = {0}; printf("Input a string: "); scanf("%s", in); // 输入字符串的时候,scanf的参数不再需要取地址符& printf("%s\n", in); }
使用字符串工具进行字符串赋值
时:
必须保证赋值结果的字符数组足够大(防止越界)
必须保证参与赋值的字符串必须合法(字符数组存在0元素)
3.2.3 字符串练习
Demo1:
char r1[1] = {1}; int i=0, e=0; for(i=0; i<strlen("abcd"); i++) { e = "abcd"[i]; // 字符串本质是一个字符数组:char anonymous[5] = "abcd"; // "abcd"[i]就相当于anonymous[i] // 再到后续数组与指针的分析中:数组名代表了数组首元素的地址, // "abcd"代表了这段内存空间的首地址,可以看做一个常量指针 // 然后进行指针运算,*(p+i)<==>p[i],就得到了数组里的每个值 printf("%d ", e); // 97 98 99 100 } strcat(r1, "abcd"); // error,r1中没有0元素,不是个字符串。此时结果未定义 printf("r1 = %s\n", r1); // undefined char r2[10] = ""; // r2代表的字符串是"" strcat(r2, "abcd"); // 将"abcd"追加到r1后面 printf("r2 = %s\n", r2); // abcd
Demo2:
char r[2] = {'a', 'b', 0}; // too mant arguments // 这样写在gcc编译器中可以编译的过,但是有warning的 printf("sizeof(r) = %d\n", sizeof(r)); // 2
Demo3:
// s的长度是? char s[10] = "\n\\\r"; // 答:题目用一个字符串字面量去初始化一个字符数组,然后问“字符串变量”s的长度是多少,即 printf("strlen(s) = %d\n", strlen(s)); // 3,\n是一个换行符;\\是一个反斜杠符'\';\r是一个回车符 // 如果问的是s的大小,则应该是sizeof(s) = 10;
Demo4:
// 下面的字符串赋值正确的是: char str1[] = {"string"}; char str2[6] = {0}; char str3[8]; A. strcpy(str1, "Delphi"); // ok,字符串拷贝,也没有越界 B. strcpy(str1, str3); // error, undefined, str3不是个字符串(没有包含0元素) C. strcpt(str2, str1); // error, undefined, 越界,str2只有6个字节大小,而str1需要7个字节大小 D. strcpy(str3, str1); // ok, 字符串赋值给字符数组
Demo5:
// 写demo去掉字符串中的'\0' char s[] = {"abcd\0ef\0gh"}; int len = sizeof(s) / sizeof(s[0]); int i = 0; while(i < len) { if(s[i] == 0) { int j = 0; for(j=i+1; j<len; j++) { s[j-1] = s[j]; } len--; } else { i++; } } printf("%s\n", s);
本文总结自“狄泰软件学院”唐佐林老师《C语言入门课程》。
如有错漏之处,恳请指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。