C语言基础知识梳理(二)数组和字符串专题

目录

五、数组和字符串

5.1 数组的基本操作

1、数组的定义

2、数组元素的赋值和访问

3、数组元素的遍历

5.2 多维数组

1、二维数组

2、多维数组

 5.3 字符串

1、字符数组和字符串的区别

2、字符串的初始化

3、字符串的输入输出

4、字符串的追加


五、数组和字符串

数组就是内存中连续的相同类型的空间变量

5.1 数组的基本操作

1、数组的定义

        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]; //这种写法是错误的,数组的元素个数只能是常量或者常量表达式,不能是变量

2、数组元素的赋值和访问

        数组元素可以重新赋值或者访问,也可以参与计算,用 数组名[索引]  即可调用,注意索引从0开始。

    arr[1] = arr[0] * 2;

3、数组元素的遍历

        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;

5.2 多维数组

1、二维数组

        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]); //二维数组某元素的地址

2、多维数组

         格式: 数据类型 数组名[第一层元素个数][第二层元素个数]…[第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]));
	

 5.3 字符串

1、字符数组和字符串的区别

  •         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

2、字符串的初始化

        通过上述的了解,我们来系统总结一下,字符串的初始化方法

        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 停止符

3、字符串的输入输出

       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

4、字符串的追加

    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++的 更新完,谢谢各位小伙伴的支持❤️

你可能感兴趣的:(C,C++系列,c语言)