09 重忆C之 字符串

在之前的学习中,我们曾经使用过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个字符拼上去。大家可以通过搜索引擎具体了解一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • 作者 谢恩铭,公众号「程序员联盟」(微信号:coderhub)。转载请注明出处。原文:https://www.ji...
    程序员联盟阅读 2,409评论 3 33
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,639评论 18 139
  • 一、字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 s...
    JaiUnChat阅读 1,655评论 0 7
  • 莫不过 是走不出自己 跌在了坑里 却自己 把坑挖的越深 直至双手沾了红 还是不知疼惜 也曾深深怀疑 深...
    夏小时阅读 173评论 0 0
  • 缘起:明明德于天下 《大学》,在我大学毕业之前,与它都没有任何连接,大概是读研究生时,本科的同学给我发过一个消息问...
    止弌阅读 358评论 0 1