C字符串和字符串函数(二)
C字符串和字符串函数(二)
字符串输入
声明字符串的第一件事:
- 分配存储空间
- 存储稍后要读入的字符串
注意指针声明的字符串: -> 本质上是要注意指针的特性
示例:
char *name; scanf("%s", name);
注意:
-
name
可能会擦写掉程序中的数据或代码,因为name
是未初始化指针 -
scanf()
函数是把信息拷贝至参数指定的地址上 -
name
未曾初始化,所以可能会指向任何地方 -
scanf()
智能读取一个单词,整行读取需要用到函数gets()
整行读取示例代码:
/**
* @Author: Lucifer
* @Date: 5/21/2023, 7:34:03 PM
* @LastEditors: Lucifer
* @LastEditTime: 5/21/2023, 7:34:03 PM
* Description: 正行读取字符串函数 - gets() puts()
* Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
*/
# include<stdio.h>
# define STLEN 81
int main(void)
{
char words[STLEN];
puts("输入一串字符串:");
gets(words);
printf("你输入的字符串是:");
printf("- print %s.\n", words);
puts(words);
puts("Done.");
getchar();
return 0;
}
注意:
gets()
函数唯一参数是words
,无法检查数组是否装得下输入行- 由于数组名会转换成数组首元素地址,所以只知道开始并不知道数组有多少元素
带来的问题:
- 缓冲区溢出 -> 多余的字符超出了指定的目标空间
- 长期以往会占用未使用的内存
替代品fgets()
fgets()
函数特点:
- 第2个参数指明了读入字符的最大数量,读取到
n-1
个字符,n
是形参 fgets()
读取到换行符会存储换行符fgets()
第三个参数指明要读入的文件,如果是从键盘读入数据的话,那么以stdin
(标准输入)作为参数
示例代码:
/**
* @Author: Lucifer
* @Date: 5/21/2023, 7:59:47 PM
* @LastEditors: Lucifer
* @LastEditTime: 5/21/2023, 7:59:47 PM
* Description: fgets()函数初体验,关注fgets()函数存储的特性
* Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
*/
# include<stdio.h>
# define STELN 14
int main(void)
{
char words[STELN];
puts("请输入一个字符串:");
fgets(words, STELN, stdin);
printf("字符串 (puts(), then fputs()):");
puts(words); // 第一行输入比fgets()读入的整行输入短,所以apple pie\n\0被存储在数组中
fputs(words, stdout);
puts("输入字符串:");
fgets(words, STELN, stdin);
printf("字符串 (puts(), then fputs()):");
puts(words);
fputs(words, stdout);
puts("Done.\n");
getchar();
return 0;
}
注意:
fgets()
函数返回指向char
的指针,该函数返回的地址与传入的第一个参数相同- 函数读到文件末尾,返回一个特殊指针(
空指针
) -> 需要处理这种特殊情况
处理空指针示例代码:
/**
* @Author: Lucifer
* @Date: 5/21/2023, 8:12:06 PM
* @LastEditors: Lucifer
* @LastEditTime: 5/21/2023, 8:12:06 PM
* Description: fgets()函数的使用
* Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
*/
# include<stdio.h>
# define STELN 10
int main(void)
{
char words[STELN];
puts("输入字符串(q退出):");
while (fgets(words, STELN, stdin) != NULL && words[0] != '\n')
fputs(words, stdout);
puts("Done.");
getchar();
return 0;
}
注意:
-
每次读取的字符数量是
STELN - 1
个字符 -
输入的内容是
By the way, the gets() functyion
-> 读取到tion\n
时将其存储为tion\n\0
由fputs()
打印出 -
因为存储了一个换行符,
fputs()
打印出该字符串,光标被下移两行 -
系统使用了缓冲IO,用户在按下
Return
键之前,输入都被存储在临时存储区,按下Return
键之后在输入中加入换行符发送给fputs()
处理换行符示例代码:
/**
* @Author: Lucifer
* @Date: 5/21/2023, 8:27:46 PM
* @LastEditors: Lucifer
* @LastEditTime: 5/21/2023, 8:27:46 PM
* Description: 处理fgets()函数保存的最后一行的换行符\n
* Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
*/
# include<stdio.h>
# define STLEN 10
int main(void)
{
char words[STLEN];
int i;
puts("请输入字符串(空行退出):");
while (fgets(words, STLEN, stdin) != NULL && words[0] != '\n')
{
i = 0;
while (words[0] != '\n' && words[i] != '\0')
i++;
if (words[i] == '\n')
words[i] = '\0';
else // word[i] == '\0' 执行这部分代码
while (getchar() != '\n')
continue;
puts(words);
}
puts("Done.");
return 0;
}
注意:
- 处理方法是删除存储在字符串中换行符
空字符串和空指针二者区别
首先观测容易混淆的原因:
- 都可以用数值
0
表示
区别:
- 空字符串(
'\0'
)用于标记C
字符串末尾的字符,字符编码是0
,其他字符的编码不可能是0
- 空指针(
NULL
)有一个值,该值不会与任何数据的有效地址对应 -> 函数使用它返回一个有效地址,表示某些特殊情况的发生,如遇到文件结尾或未能按预期执行 - 空字符是整数类型,占用的字节是
1
字节的 - 空指针是指针类型,返回值是地址,通用占用
4
字节
gets_s()函数
作用:
处理最后一行的换行符
特点:
gets_s()
函数只从标准输入中读取数据,不需要第三个参数stdin
gets_s()
读取到换行符会丢弃,而不是存储- 如果
gets_s()
读到最大字符数都没有读到换行符,那么会:- 把目标数组中的首字符设置为空字符
- 读取并丢弃随后的输入,直至读到换行符或文件结尾 -> 返回空指针
- 调用依赖实现的"处理函数" -> 中止或者退出程序
为什么要丢弃过长输入行中的余下字符?
- 输入行中多出来的字符会被留在缓冲区当中,成为下一条语句的输入 ->
|
符号可以使用的由来 - 如果下一条语句读取的是
double
类型的值,那么可能导致程序崩溃
fgets()
函数的处理函数:
实现:
- 用空字符替代换行符
- 字符串中遇到空字符丢弃该输入行的其余字符
示例代码:
char * sgets(char * st, int n)
{
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
while (st[i] != '\n' && st[i] != '\0') // 没遇到换行符,继续读取
i++;
if (st[i] == '\n')
st[i] = '\0'; // 换行符用空字符替换
else
while (getchar() != '\n')
continue;
}
return ret_val;
}
scanf()函数
scanf()
函数与gets()
和fgets()
函数的区别:
- 如何确定字符串末尾
scanf()
函数确定字符串末尾的方式:
- 未指定字段宽度(如
%s
) -> 遇到第一个非空白字符作为字符串开始,开始之后的第一个空白字符作为字符串结束 - 指定字段宽度(如
%10s
) ->scanf()
函数将读取10
个字符,或者读到第一个空白字符终止 -> 先满足的条件就是结束输入的条件
示例代码:
/**
* @Author: Lucifer
* @Date: 5/21/2023, 9:13:46 PM
* @LastEditors: Lucifer
* @LastEditTime: 5/21/2023, 9:13:46 PM
* Description: scanf()函数处理字符串结束的方式
* Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
*/
# include<stdio.h>
int main(void)
{
char name1[11], name2[11];
int count;
printf("输入两个英文名:.\n");
count = scanf("%5s %10s", name1, name2);
printf("读取到 %d 个名字, 分别是 %s, %s.\n", count, name1, name2);
getchar();
return 0;
}
注意:
举例说明:
接收: sacnf("%5s", name)
input
: Ann Ular
-> 中间有空白字符
output
: Ann
为第一个结束点,因为第一个空白字符先进入,虽然声明了字段宽度,但是先满足的条件就是输入的结束条件 -> 后面是接着从结束点读取,所以下一个输出是 Ular
有空白字符
It's a lonely road!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话