《小菜狗 C 语言入门 + 进阶笔记》(27)字符数组

《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介


1、字符数组

1.1、引入
  1. 在 C 语言中,字符串本质是使用空字符 \0 结尾的一维字符数组
  2. 在 C 语言中,没有专门的字符串变量,没有 string 类型,通常就用一个字符数组来存放一个字符串

用来存放字符的数组称为字符数组,可以将字符串直接赋值给字符数组。

1.2、字符数组的创建和初始化
  • 创建一维字符数组
char a[10];
  • 创建字符常量并初始化字符数组
char c[20] = {'c', '  ', 'p', 'r', 'o', 'g', 'r', 'a','m'};  //给部分数组元素赋值
char c[] = {'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm' };   //对全体元素赋值时可以省去长度下标长度
  • 创建字符串常量并初始化字符数组

(1)指定数组大小

char str[20] = {"http://baidu.com"};

(2)不指定数组长度(不定长数组)。通过初始化内容来确定数组元素个数

给字符数组赋值时,我们通常使用这种写法,将字符串一次性地赋值(可以指明数组长度,也可以不指明),而不是一个字符一个字符地赋值,那样做太麻烦了。

char str[] = "http://baidu.com";   //这种形式更加简洁,实际开发中常用

数组第 0 个元素为'h',第 1 个元素为't',后面的元素以此类推。

1.3、字符常量与字符串常量

强调

‘a’ 表示是一个字符,“a” 表示一个字符串相当于 ‘a’+‘\0’;

‘’ 里面只能放一个字符;

“” 里面表示是字符串系统自动会在串末尾补一个 0。

#include <stdio.h>
int main()
{
    char arr1[] = {'a', 'b', 'c'};
    char arr2[] = "abc";
    return 0;
}

调试后,我们在监视窗口中观察是这样的:
在这里插入图片描述

在使用常量字符串初始化的时候,数组中多了⼀个 '\0' 字符;这个 '\0' 就是字符串常量中隐藏的

1.4、不定长数组与定长数组
#include <stdio.h>
int main()
{
    char arr1[] = {'a', 'b', 'c'};
    char arr2[5] = {'a', 'b', 'c'};
    return 0;
}

注意:arr1 就是 "abc",arr2 就是 "abc0"!

1.5、'\0' 字符作用解刨

先看一个代码例子。

1.5.1、初始化赋值
#include <stdio.h>
int main()
{
    char arr1[] = {'a', 'b', 'c'};
    char arr2[] = "abc";
    printf("%s\n", arr1);
    printf("%s\n", arr2);
    return 0;
}

结果分析:

abc烫烫烫?侵7(?╔?╚╔╔
abc

我们可以看到:

  • arr1 字符数组在打印的时候,打印了 a、b、c 后还打印了⼀些随机值,这就是因为 arr1 在末尾的地方没有 \0 字符作为结束标志,在打印的时候没有停止
  • 但是 arr2 的打印就是完全正常的,就是因为 arr2 数组是使⽤字符串常量初始化的,数组中有 '\0' 作为标志,打印可以正常停止

如果我们在 arr1 数组中单独放⼀个 ‘\0’ 字符会怎么样呢??

#include <stdio.h>
int main()
{
    char arr1[] = {'a', 'b', 'c', '\0'};
    char arr2[] = "abc";
    printf("%s\n", arr1);
    printf("%s\n", arr2);
    return 0;
}

结果分析:

abc
abc

看到两次打印的结果是⼀样的了,那从上述的例子我们确实能够观察到 ‘\0’ 的作⽤和重要性的。

那当不在初始化的时候赋值,在使用的时候赋值会发生什么情况呢?

1.5.2、使用时赋值

有些时候,程序的逻辑要求我们必须逐个字符地为数组赋值,这个时候就很容易遗忘字符串结束标志'\0'

下面的代码中,我们将 26 个大写英文字符存入字符数组,并以字符串的形式输出:

#include <stdio.h>
int main()
{
    char str[30];
    char c;
    int i;
    for (c=65, i=0; c<=90; c++, i++) {
        str[i] = c;
    }
    printf("%s\n", str);

    return 0;
}

在 VScode 下的运行结果:

ABCDEFGHIJKLMNOPQRSTUVWXYZ口口口口i口口0 ?

详细解释:

printf() 输出字符串时,会从第 0 个元素开始往后检索,直到遇见'\0'才停止,然后把'\0'前面的字符全部输出,这就是 printf() 输出字符串的原理

本例中我们使用 printf() 输出 str,按理说到了第 26 个元素就能检索到'\0',就到达了字符串的末尾,然而事实却不是这样,由于我们并未对最后 4 个元素赋值,所以第 26 个元素不是'\0',第 27 个也不是,第 28 个也不是……可能到了第 50 个元素才遇到'\0',printf() 把这 50 个字符全部输出出来,就是上面的样子,多出来的字符毫无意义,甚至不能显示。

数组总共才 30 个元素,到了第 50 个元素不早就超出数组范围了吗?然而,数组后面依然有其它的数据,printf() 也会将这些数据作为字符串输出。

你看,不注意 ‘\0’ 的后果有多严重,不但不能正确处理字符串,甚至还会毁坏其它数据。

要想避免这些问题也很容易,在字符串的最后手动添加'\0'即可。类似之前的做法,在循环结束后添加'\0',修改上面的代码:

#include <stdio.h>
int main()
{
    char str[30];
    char c;
    int i;
    for (c=65,i=0; c<=90; c++,i++) {
        str[i] = c;
    }
    str[i] = 0;  //此处为添加的代码,也可以写作 str[i] = '\0';
    printf("%s\n", str);
   
    return 0;
}

第 9 行为新添加的代码,它让字符串能够正常结束。根据 ASCII 码表,字符'\0'的编码值就是 0。 但是,这样的写法貌似有点业余,或者说不够简洁,更加专业的做法是将数组的所有元素都初始化为“零”值,这样才能够从根本上避免问题

再次修改上面的代码:

#include <stdio.h>
int main()
{
    char str[30] = {0};  //将所有元素都初始化为 0,或者说 '\0'
    char c;
    int i;
    for (c=65,i=0; c<=90; c++,i++) {
        str[i] = c;
    }
    printf("%s\n", str);
   
    return 0;
}
1.6、注意

这里还需要留意一个字符数组只有在定义时才能将整个字符串一次性地赋值给它,一旦定义完了,就只能一个字符一个字符地赋值

请看下面的例子:

char str[7];
str = "abc123";  //错误
//正确
str[0] = 'a'; str[1] = 'b'; str[2] = 'c';
str[3] = '1'; str[4] = '2'; str[5] = '3';

2、判断数组中是否包含某个元素

在实际开发中,经常需要查询数组中的元素。

不幸的是,C 语言标准库没有提供与数组查询相关的函数,所以我们只能自己编写代码。

2.1、对无序数组的查询

所谓无序数组,就是数组元素的排列没有规律。无序数组元素查询的思路也很简单,就是用循环遍历数组中的每个元素,把要查询的值挨个比较一遍。

请看下面的代码:

#include <stdio.h>
int main()
{
    int nums[10] = {1, 10, 6, 296, 177, 23, 0, 100, 34, 999};
    int i, num, thisindex = -1;
   
    printf("Input an integer: ");
    scanf("%d", &num);
    for (i=0; i<10; i++) {
        if (nums[i] == num) {
            thisindex = i;
            break;
        }
    }
    if (thisindex < 0) {
        printf("%d isn't  in the array.\n", num);
    } else {
        printf("%d is  in the array, it's index is %d.\n", num, thisindex);
    }

    return 0;
}

运行结果:

Input an integer: 100↙
100 is  in the array, it's index is 7.
或者
Input an integer: 28↙
28 isn't  in the array.

详细解释:

这段代码的作用是让用户输入一个数字,判断该数字是否在数组中,如果在,就打印出下标。

第 10~15 行代码是关键,它会遍历数组中的每个元素,和用户输入的数字进行比较,如果相等就获取它的下标并跳出循环。

注意:

数组下标的取值范围是非负数,当 thisindex >= 0 时,该数字在数组中,当 thisindex < 0 时,该数字不在数组中,所以在定义 thisindex 变量时,必须将其初始化为一个负数。

2.2、对有序数组的查询

查询无序数组需要遍历数组中的所有元素,而查询有序数组只需要遍历其中一部分元素。例如有一个长度为 10 的整型数组,它所包含的元素按照从小到大的顺序(升序)排列,假设比较到第 4 个元素时发现它的值大于输入的数字,那么剩下的 5 个元素就没必要再比较了,肯定也大于输入的数字,这样就减少了循环的次数,提高了执行效率。

请看下面的代码:

#include <stdio.h>
int main()
{
    int nums[10] = {0, 1, 6, 10, 23, 34, 100, 177, 296, 999};
    int i, num, thisindex = -1;
   
    printf("Input an integer: ");
    scanf("%d", &num);
    for (i=0; i<10; i++) {
        if (nums[i] == num) {
            thisindex = i;
            break;
        } else if (nums[i] > num) {
            break;
        }
    }
    if (thisindex < 0) {
        printf("%d isn't  in the array.\n", num);
    } else {
        printf("%d is  in the array, it's index is %d.\n", num, thisindex);
    }
   
    return 0;
}

详细解释:

与前面的代码相比,这段代码的改动很小,只增加了一个判断语句,也就是 12~14 行。因为数组元素是升序排列的,所以当 nums[i] > num 时,i 后边的元素也都大于 num 了,num 肯定不在数组中了,就没有必要再继续比较了,终止循环即可。

《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介


每日一更!

公众号、优快云等博客:小菜狗编程笔记

谢谢点赞关注哈!目前在飞书持续优化更新~

日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小菜狗编程笔记

你的鼓励将是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值