目录
五、数组和字符串
5.1 数组的基本操作
1、数组的定义
2、数组元素的赋值和访问
3、数组元素的遍历
5.2 多维数组
1、二维数组
2、多维数组
5.3 字符串
1、字符数组和字符串的区别
2、字符串的初始化
3、字符串的输入输出
4、字符串的追加
数组就是内存中连续的相同类型的空间变量
1)数组定义的基本格式:
数据类型 数组名[元素个数] = {值1, 值2, 值3};
数组名不仅表示该数组的名字,还可以表示该数组的首地址,这种给所有元素都复制,称为“完全初始化”,这个时候,[ ]里的元素个数可以省略。
int arr[3] = {1,2,3};
int arr1[] = {1,2,3};
2)如果定义数组的时候,{ }中的数值个数 < [ ]中的元素个数,则是“不完全初始化”,其他位置会自动补0;注意不能只写了{},里边一个值都没有
int arr2[4] = {1,2}; //最后的数组遍历出来会是 1,2,0,0
3)如果只声明一个数组,并没有进行赋值,就是“完全不初始化”,输出这个数组各个元素的位置信息时,会是乱码,如果后续再进行赋值,其他位置上的数据仍是乱码,这个时候,[ ]里的元素个数不可以省略。
int arr3[3]; //如果数组没有赋值,输出各个位置是乱码
arr3[1] = 1; //再赋值,其他位置仍是乱码
4)要注意,数组元素的个数只能是常量或常量表达式,不能是变量,例如下边的是错误的
int i = 3;
int arr4[i]; //这种写法是错误的,数组的元素个数只能是常量或者常量表达式,不能是变量
数组元素可以重新赋值或者访问,也可以参与计算,用 数组名[索引] 即可调用,注意索引从0开始。
arr[1] = arr[0] * 2;
1)通过for循环输出每个元素的值
for (int i = 0 ; i
2)输出数组在内存中的存储方式和大小,用sizeof来计算
//数组在内存中存储方式和大小
for (int i = 0 ; i<10;i++)
{
printf("%p\n", &arr[i]);//连续的空间,
}
printf("%p\n", &arr); //数组名是一个地址常量,指向数组首地址
printf("%d\n", sizeof(arr));// 12,数组大小=数据类型*元素个数
//数组元素个数
printf("数组元素个数:%d\n", sizeof(arr)/sizeof(arr[0]));
return EXIT_SUCCESS;
1)二维数组的定义
格式: 数据类型 数组名[行][列];
以二维数组为例,有多种初始化的方式,可以达到不同的效果:
//二维数组定义和初始化
int arr[2][3] = {{1,2,3}, {4,5,6}};
int arr[2][3] = {1,2,3,4,5,6}; //这样定义也可以,跟上边那行效果一样
int arr[][3] = {1,2,3,4,5,6}; //行数可以省略,但是列数必须写
int arr[][3] = {1,2,3,4,5,6,7}; //也对,最后3个不够的位置补0
2)二维数组的遍历,用两层嵌套的for循环
//二维数组遍历
for(int i = 0;i<2;i++)
{
for(int j = 0; j<3;j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
3)二维数组的大小
//二维数组大小
printf("二维数组大小:%d\n",sizeof(arr)); //行*列*sizeof(数据类型)
printf("二维数组一行大小:%d\n", sizeof(arr[0]));
printf("二维数组元素大小:%d\n", sizeof(arr[0][0]));
printf("二维数组行数:%d\n", sizeof((arr)/(arr[0]));
printf("二维数组列数:%d\n", sizeof(arr[0]/arr[0][0]));
4)二维数组的地址
//二维数组地址
printf("%p\n", &arr); //二维数组首地址
printf("&p\n", &arr[0]); //二维数组第一行首地址
printf("&p\n", &arr[0][0]); //二维数组某元素的地址
格式: 数据类型 数组名[第一层元素个数][第二层元素个数]…[第n层元素个数];
1)三维数组的定义、遍历和大小
//三维数组定义
//数据类型 数组名 [层][行][列]
//层数可以省略
int a[2][3][4] =
{
{
{1,2,3,4},
{2,3,4,5},
{3,4,5,6}
},
{
{1,2,3,4},
{2,3,4,5},
{3,4,5,6}
}
}
//三维数组的遍历
for(int i = 0; i < 2; i++)
{
for(int j = 0 ; j < 3; j++)
{
for(int k = 0; k<4;k++)
{
printf("%d\t",a[i][j][k]);
}
printf("\n");
}
}
printf("三维数组大小:%d\n",sizeof(a)); //2*3*4*4
printf("三维数组一层大小:%d\n", sizeof(a[0]));
printf("三维数组一行大小:%d\n", sizeof(a[0][0]));
printf("三维数组元素大小:%d\n", sizeof(a[0][0][0]));
printf("层:%d\n",sizeof(a)/sizeof(a[0]));
printf("行:%d\n", sizeof(a[0])/sizeof(a[0][0]));
printf("列:%d\n", sizeof(a[0][0])/sizeof(a[0][0][0]));
- C语言中没有string,可以通过char数组赖代替
- 数字0(和字符 ‘\0’ 等价)结尾的char数组就是一个字符串,
- 字符串是一种特殊的char的数组
1)定义字符数组,代码如下,声明的时候只有5位,写入的字符串也刚好5位,并且没有以 \0 结尾,就仅是一个字符数组,并不是一个字符串
char arr[5]={'h','e','l','l','o'};
2)定义字符串,字符串的结束标志为 \0,用下边的方式定义字符串,会在最后补上 \0
char arr1[] = "hello"; //大小是6 因为自动在最后存上\0
字符串是字符数组的一个特例,当最后一位是 \0 时,就认为这是一个字符串,所以也可以通过定义字符数组的方式来定义字符串,可以有这两种方式:①最后一位自己补 \0,如arr2 ;②声明数组的时候,元素的个数声明的多一点,空余位置会自动补0,这里相当于 \0,就也是字符串
char arr2[] = {'h','e','l','l','o','\0'};
char arr3[6] = {'h','e','l','l','o'};//这个就说空余的最后一位补0,这里相当于\0 与arr2等价,也是一个字符串
注意: 数字0 等同于 \0,是ASCII码是0,表示null,并不是指自己输入的‘0’, 自己输入的0转换为ASCII码是 48。所以下边的自己补‘0’ 的写法是并不会成为一个字符串的。
char arr4[] = {'h','e','l','l','o','0'}; //自己写的'0'不是\0,不是字符串
3)字符串的输出,用 %S,注意,输出字符串是正常的,但是输出没有 \0 结尾的字符数组,时候,后边会乱码,因为是一直输出到 \0才停止,所以遇不到\0 ,字符串会一直往后走
printf("%s", arr1);//用占位符%s 可以输出字符串arr1,arr2,arr3
printf("%s", arr); //输出没有\0的字符数组,后边会乱码
4)字符数组的输出,用for循环
for (int i = 0; i < sizeof(arr); i++)
{
printf("%c", arr[i]);
}
printf("%d\n", sizeof(arr));//1*5
通过上述的了解,我们来系统总结一下,字符串的初始化方法
1)不指定长度,没有0结束符,有多少个元素就有多长,不能成功成为一个字符串
char a[] = {'a','b','c'}; //不指定长度,没有0结束符,有多少个元素就有多长
printf("%s\n", a); //乱码
2)指定长度,后边没有赋值的元素,自动补0
char a1[100] = {'a','b','c'};
char a2[100] = {"hello"};
printf("%s\n", a1); //都不会乱码因为补0了
3)直接初始化字符串
char arr[] = "hello"; //可以,不指定长度,自动补\0
char arr1[7] = "hello"; //可以,声明的元素个数只要≥ 字符串个数+1就可以,加的1就是 \0的位置
char arr2[5] = "hello"; //不可以,因为需要补\0,声明的空间不够,会报错
printf("%s\n",arr1 );
如代码注释中写的,用这种方法初始化字符串的时候,要么不指定长度,要么指定的长度,需要比字符个数至少多1个,多的一位是为了给 \0留位置。
4)ASCⅡ码初始化字符串
注意,带引号,就表示这个数字,但是不带引号,就是这个数字对应的ASCⅡ码
char arr2[] = {120,121,122,0,123,98,99};
printf("%s\n",arr2 ); //只输出0前边的,xyz, 因为到0 就停止了
char a5[50] = {'1','2','0','4','5'};
printf("%s\n",a5 ); //输出 12045 , 这里的'0' 不是 \0 停止符
1-4 的输入输出部分需要头文件 #include
1)用 scanf 输入 ,用printf 来输出
scanf 和 printf 是格式化操作,可以根据不同的格式来实现输入输出
特别注意在用scanf的时候,要留一个位置存储 "\0" ,所以声明的长度为10的数组,只能输入长度为9的字符串,代码如下,
//定义字符数组存储字符串
char ch[10];
//虽然定义的长度为10,但是在scanf输入的时候,只能输入长度为9的字符串,因为最后一位要存\0
scanf("%s", ch); //注意,scanf接受空格或换行 均会结束
printf("output:%s\n", ch);
注意:scanf接受空格或换行 均会结束,如果想用 scanf 接收带空格的字符串,可以通过正则表达式 [^\n] ,表示接受所有 非\n 的所有内容
scanf("%[^\n]", ch); //^表示非, [^\n]表示除了换行符
//一整句的意思就是,接受除了\n 之外的所有字符
2)用 gets() 函数 来接收输入
gets() 函数可以从标准输入读入字符,并保存到s指定的内存空间,只要出现换行符或者读到文件结束位置,注意,gets() 可以直接接受空格,必须遇到换行符或者读到文件结尾才结束。
char s[100];
printf("请输入字符串");
gets(s); //gets可以接受空格,在遇到换行符或文件结尾才结束
scanf 和 gets() 函数都并不安全,会产生溢出问题
3)用 fgets() 函数 输入
fgets() 获取输入的时候,会把用户输入的回车也作为字符串的一部分,也可以接受空格,通过scanf 和 gets() 获取的时候,不包含结尾的 "\n" ,但通过fgets 保存的字符串 ,也会存上用户在结尾的 "\n"。
fgets()函数需要指定最大读取的字符串长度,输入的再多,就不接受了这样是安全的,不存在缓冲区溢出的问题。
所以如果fgets 可以保存的字符串长度大于输入的元素个数,最后一个可以存\n,如果小于输入的元素个数,可能就存不上\n 了
char str[100];
//用 fget获取输入
fget(str, sizeof(str), stdin);
/*
第二个参数 要指定最大读取字符串的长度,即字符串大小
第三个参数 指定文件指针,若是键盘输入的字符串,固定写为 stdin
*/
printf("str = \"%s\"\n", str);
3)用 puts() 输出
puts 输出字符串,遇到 \0 停止,在输出完成后自动换行,
char ch[] = "hello world";
//puts 在输出完成后,自动换行
puts(ch);
//puts 遇到 \0 会直接停止
puts("hello\0 world");
//可以直接用一个puts 来日常换行
puts("");
4)用 fputs() 输出
可以将指定字符串 写入 指定文件中,字符串结束符 \0 不会写入文件, fputs是 puts的 文件操作版本
char ch[] = "hello world";
fputs(ch, stdout); //第二个参数是文件指针,如果输出到控制栏,就写stdout
5)strlen() 计算指定字符串长度
需要头文件 #include
可以用来计算指定字符串的有效长度,不包含字符串结束符 \0, 如果用sizeof查出来的是包含\0的
//strlen可以用来计算字符串有效个数
//感受一下 sizeof和 strlen的区别
char ch[100] = "hello world";
printf("数组大小:%d", sizeof(ch)); // 100
int n = strlen(ch); // 返回值是无符号int类型
printf("字符串长度:%d", strlen(ch)); // 11
//如果不知名数组大小呢
char ch2[] = "hello world";
printf("数组大小:%d", sizeof(ch2)); // 12
printf("字符串长度:%d", strlen(ch2)); // 11
char str1[] = “abcdef”;
char str2[] = “123456”;
char dst[100];
有如上的字符串,将str2 追加到str1之后,保存在dst中,代码如下:
int i = 0;
while(str1[i] != 0){
dst[i] = str1[i];
i++;
}
int j = 0;
while(str2[j] != 0){
dst[i+j] = str1[j];
j++;
}
dst[i+j] = 0 ;//字符串结束符
写在最后:
课程听的是 黑马程序员的c语言课,链接如下:黑马程序员C语言基础教程【源码,笔记,软件,案例全,初学者值得收藏的教程】_哔哩哔哩_bilibili
上一篇的C语言的笔记链接:
C语言基础知识梳理(一)_爱学习的小船的博客-CSDN博客_c语言基础知识梳理希望我还会继续把c和 c++的 更新完,谢谢各位小伙伴的支持❤️