美文网首页
09 重忆C之 字符串

09 重忆C之 字符串

作者: 夏威夷的芒果 | 来源:发表于2017-08-29 16:09 被阅读13次

在之前的学习中,我们曾经使用过printf函数对字符串进行输出。那么,如果我们希望输入一个字符串到变量,我们可以怎么做呢?

第一种:scanf
希望接收一个字符串到string这个变量。可以使用scanf("%s", string);这里写的并不是&string而是string。因为在 C 语言中,数组名直接可以被当做数组所在内存的地址使用。输出的时候可以使用printf("%s\n");来输出
对于如下代码:

#include <stdio.h>
int main() {
    char string[10];
    // 请在这里使用 scanf
    scanf("%s", string);
    printf("%s\n",string);
    return 0;
}

点击 运行 测试一下程序,看看如果你输入hello worlditisverylongforittostore分别会有怎样的结果?

当输入hello world时,被输出的只有hello。这是因为scanf在遇到空格时就已经终止读入了。

当输入一个很长的字符串时,就出现了 Segmentation Fault(段错误)。因为声明的字符数组长度只有 10,我们已经在程序运行时,让它写入了“不属于它”的内存空间。

来看看第二种:

嵌入占位符

#include <stdio.h>

int main() {
    char information[100];
    char *name = "Li, Lei";
    char *gender = "male";
    int age = 14;
    float height = 187.5f;
    // 在这里使用 sprintf
    sprintf(information, "%s is a %s. He is %d-year-old and %fcm tall.", name, gender, age, height);
    printf("%s", information);
}

输出为
Li, Lei is a male. He is 14-year-old and 187.500000cm tall.

sprintfinformation这一字符串中写入了一个格式化输出的结果,依照字符串格式描述,一系列intfloat等类型的数据被“嵌入”到了格式字符串的占位符位置,并最终写入到了information中。
即将一系列的变量按照指定格式写入到一个字符串中。

sprintf可用于各种数据的格式化:

  • 第一个参数是被写入的字符串;
  • 第二个参数是写入的格式;
  • 之后的参数是依次会被写入的数据。

在这里要提醒一下,我们一定要注意用于第一个参数的字符串声明时的长度,如果它所对应的内存空间不足,我们现在的这种用法就可能会触发段错误。

字符串长度

头文件#include <string.h>
使用方法:

strlen(字符串字面量或者变量)    //返回得到的是其长度(不带末位\0)

复制字符串

strcpy(copy, string);       //第二个参数是被复制的字符串,第一个参数是需要复制到的目标字符串变量位置

在程序中通过strcpy完成了复制的过程后,copy中就和string中的字符串是一致的了。

要注意一下,在使用strcpy时要确保目标字符串的声明长度可以装得下,否则程序运行时则可能会出现段错误。

为避免此问题,在工程中更多的鼓励使用增加了第三个“复制长度”参数的strncpy函数。即只把前n个字符复制上去。

字符串的字典序(比较)

在数学中诸如 10 < 20这样数字的大小关系是天然定义的,可是对于字符、字符串来说,他们有“大小”关系吗?

当我们把"China"和"America"放在一起的时候,我们可以说它们这两个字符串其中有一个大于另外一个么?这个问题的回答是——“有”。

C 语言中对于字符的比较依赖的是字符的编码,C 语言中默认使用了 ASCII(American Standard Code for Information Interchange,美国标准信息交换码)作为编码标准,每一个字符都对应了一个整数值。常见的一些字符和他们对应的编码值如下:

ASCII码

通过参考列出的 ASCII 码参考表(局部),在 C 语言中,字符直接进行大小的比较时,会对它们的编码值进行比较。因此,'A'小于'B','A'小于'a'。

C 语言中,通常遵循一种特殊定义——字典序(lexicographical order)。
说白了就是后面的比前面的大,有比没有大。
"abc" < "bbc"

  • 对于字符串"abc""bbc"的大小关系——
    我们首先会对它们的第一个字符进行比较,
    我们发现第一个字符'a'< 'b'时,
    我们就可以明确"abc" <"bbc"的结论。

"abc" < "abd"

  • 对于字符串"abc""abd"的大小关系——
    我们首先会对它们的第一个字符进行比较,
    如果第一个字符相同,则会接下来比较第二个字符;
    如果第二个字符相同,则会接下来比较第三个字符,
    当我们发现第三个字符'c'<'d'时,我们就得到了"abc"< "abd"的结论。

"ab" < "abc"

  • 对于字符串"abc""ab"的大小关系——
    我们首先会对它们的第一个字符进行比较,
    如果第一个字符相同,则会接下来比较第二个字符;
    如果第二个字符相同,则会接下来比较第三个字符,
    当我们发现"ab"没有第三个字符时,我们就得到了"ab"< "abc"的结论。

总结:

  • 字典序遵循 逐字符比较的方式,越靠左的字符越会被先比较。
  • 逐字符比较过程中,一旦发现某一对被比较的字符之间不相等时,这一对字符的大小关系即为这一对字符串的大小关系。
  • 逐字符比较过程中,一旦出现某一个字符串的所有字符都已经经过比较,而另一字符串还存在未被比较的字符时,较短的字符串更小。
  • 如果所有字符串内的字符都被发现相等,则这两个字符串相等。
    因此,字符串"China"大于"America"。

比较的语句 strcmp(input, string);

input小于string时返回了负数,当input等于string时返回了 0,当input大于string时返回正数呢?

我们可以通过在if的条件中写:
strcmp(input, string) == 0
来判断两个字符串是否相同。也可以将等号改为大于号、小于号来判断字符串的大小关系。

问题:

输入 10行不含有空格的字符串,对应十个学生姓名(长度大于 0 小于 20)。
输出为 101行,为排序后的 10 个学生姓名,每个学生姓名单独占一行。

样例输入

Alice
Bob
Gary
Harry
Ivn
Julia
Danis
Fone
Candy
Evan

样例输出

Alice
Bob
Candy
Danis
Evan
Fone
Gary
Harry
Ivn
Julia

代码

#include <stdio.h>
#include <string.h>
void swap(char a[20], char b[20]){
    char c[20];
    strcpy(c, a);
    strcpy(a, b);
    strcpy(b, c);
}
int main() {
    char arr[10][20];
    int i,j;
    for (i = 0; i < 10; i++){
        scanf("%s",arr[i]);
    }
    for (i = 0; i < 10; i++ ){
        for (j = 0; j < 9; j++){
            if (strcmp(arr[j],arr[j+1])>0){
                swap(arr[j],arr[j+1]);
            }
        }
    }
    for (i = 0; i < 10; i++){
        printf("%s\n",arr[i]);
    }
}

字符串拼接

strcat(A, B);会把参数的第二个字符串(含\0)加在第一个字符串的/0位置
strcat函数将第二个参数的字符串(含\0)拷贝到第一个参数的字符串\0所在内存位置及之后。所以,我们通过

strcat(hello, world);
就会改变hello的值,让"hello "之后多出了"world"这段字符串
(假设char hello[100] = "hello "; char world[100] = "world";)。

类似于strcpy函数,在使用strcat函数时,也要注意内存安全问题。如果被连接上新内容的目标字符串的声明长度不够长,程序就可能出错。相应工程中也更鼓励使用增加了第三个“追加长度”参数的strncat函数,即只把前n个字符拼上去。大家可以通过搜索引擎具体了解一下。

相关文章

  • 09 重忆C之 字符串

    在之前的学习中,我们曾经使用过printf函数对字符串进行输出。那么,如果我们希望输入一个字符串到变量,我们可以怎...

  • 08 重忆C之 字符串与数组

    题目:统计字符: 在 30 个字符组成的一行输入中包括了大写字母、小写字母、数字和空格(值包含空格,不包含\t一类...

  • 07 重忆C之 数组

    数组索引 这样声明个数组,名为radius,含3个int型元素。我们可通过radius[0],radius[1],...

  • 03 重忆C之 运算

    计算

  • 05 重忆C之 边角

    自增与输出 输出 2 输出 3 假设现在a的取值为5,上面这两行代码中第一句会输出的值是5;而同样在a取值为5的情...

  • 06 重忆C之 函数

    调用 首先要理解的是函数的 定义(define) 和 调用(call)。被抽出的函数is_prime的整体被称为函...

  • 我和C君的故事(一)

    和C君分别已有四年之久,虽久未联络,然思念之心益重,每每思及与C君诸多趣事,皆有忆之成文之心。近日有暇,作文以记之...

  • C语言 字符串反转

    C语言 之 字符串反转

  • redis 数据结构

    String 数据结构 示例 这里就可以存储"Redis C",而C只能读取Redis字符串 对C字符串和SDS之...

  • 13 重忆C 之 工程开发命令

    pwd返回了根目录 这时候看到系统返回了一个 /,这个 / 被我们称为系统的 根目录(root),这个位置也就是我...

网友评论

      本文标题:09 重忆C之 字符串

      本文链接:https://www.haomeiwen.com/subject/gpjgdxtx.html