《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
目录
1、字符
所谓字符
就是我们在键盘上敲出来的单个符号,如: A, a, 1, @, #, $, ~ 等等,C 语⾔规定,字符必须要放在单引号中。
前面 (2.6)常量 - 转义字符 - ASCII 码 章节说过数据类型 char
,专门⽤来创建字符变量,而字符变量
是⽤来存储字符
的。这些字符要想存储起来,就得放在字符变量中,比如:
char ch = 'a';
2、字符串
C 语⾔中有字符类型,但是没有字符串类型,字符串
就是由双引号引起来的⼀串字符
,比如:"abcdef"
;
⼀个字符串中我们直观的能看到⼀些字符,比如:字符串常量 “abcdef” 中,我们看到了 a、b、c、d、e、f 这 6 个字符,但是实际上在末尾还隐藏
⼀个 '\0'
的 转义字符
(参考 前面 (2.6)常量 - 转义字符 - ASCII 码 章节 ) 作为字符串结束标志
。
注意: 字符串常量的实际字符数总是比其双引号中的字符数多 1,编码过程中的易错点。
3、'\0'
详解
字符串是一系列连续的字符的组合,要想在内存中定位一个字符串,除了要知道它的开头,还要知道它的结尾。
找到字符串的开头很容易,知道它的名字(字符数组名或者字符串名)就可以;
然而,如何找到字符串的结尾呢?
- 在 C 语言中,字符串总是以
'\0'作为结尾
,所以'\0'
也被称为字符串结束标志
。
'\0'
是 ASCII 码表中的第 0 个字符,英文称为NULL
,中文称为“空字符”。该字符既不能显示,也没有控制功能,输出该字符不会有任何效果,它在 C 语言中唯一的作用就是作为字符串结束标志
。
- 由
" "
包围的字符串会自动在末尾添加'\0'
。
例如,"abc123"
从表面看起来只包含了 6 个字符,其实不然,C 语言会在最后隐式地添加一个'\0'
,这个过程是在后台默默地进行的,所以我们感受不到。
比如以下图示:
用双引号括起来的字符串
: "hello, world"
, "A"
, ""
。
- C 语言在
处理字符串
时,从前往后逐个扫描字符,一旦遇到 '\0' 就认为到达了字符串的末尾
,就结束处理。
因此:
'\0'
至关重要,没有'\0'
就意味着永远也到达不了字符串的结尾。
4、单个字符
输入单个字符可以使用 scanf() 这个通用的输入函数,对应的格式控制符为%c
,之前 (2.8)输入 & 输出语句(1) 章节已经讲到了。
4.1、int getchar(void)
函数从屏幕读取下一个可用的字符,并返回为一个整数。它的原型定义在头文件 stdio.h 。
- 程序运行到这个命令就会暂停,等待⽤户从键盘输⼊。
- 注意这个函数在
同一个时间内只会读取一个单一的字符
,等同于使⽤ scanf() 方法读取⼀个字符。 - getchar() 不会忽略起⾸的空白字符,总是返回当前读取的第⼀个字符,
⽆论是否为空格
。 - 如果读取失败,返回常量 EOF,由于 EOF 通常是 -1 ,所以返回值的类型要设为 int,而不是 char。
它就是
scanf("%c", c)
的替代品,除了更加简洁,没有其它优势了;或者说,getchar() 就是 scanf() 的一个简化版本。
4.2、int putchar(int c)
函数把字符输出到屏幕上,并返回相同的字符。它的原型定义在头文件 stdio.h 。
- putchar() 函数将它的参数字符输出到屏幕。
- 这个函数在
同一个时间内只会输出一个单一的字符
,等同于使⽤ printf() 输出⼀个字符。 - 操作成功时, putchar() 返回输出的字符,否则返回常量 EOF。
可以在循环内使用这个方法,以便在屏幕上输入和输出多个字符。
举例代码如下:
#include <stdio.h>
int main( )
{
int c;
printf( "Enter a value :");
c = getchar( );
printf( "\nYou entered: ");
putchar(c);
printf( "\n");
return 0;
}
当上面的代码被编译和执行时,它会等待您输入一些文本,当您输入一个文本并按下回车键时,程序会继续并只会读取一个单一的字符,显示如下:
Enter a value :runoob
You entered: r
一句话总结:
在接受单个字符和打印单个字符
的时候,可以使⽤ getchar 和 putchar。
思维导图:
4.3、getche() 和 getch()
4.3.1、getche()
它没有缓冲区,输入一个字符后会立即读取,不用等待用户按下回车键,这是它和 scanf()、getchar() 的最大区别
。
请看下面的代码:
#include <stdio.h>
#include <conio.h>
int main()
{
char c = getche();
printf("c: %c\n", c);
return 0;
}
输入示例:
@c: @
输入@
后,getche() 立即读取完毕,接着继续执行 printf() 将字符输出,所以没有按下回车键程序就运行结束了。
4.3.2、getch()
getch() 也没有缓冲区,输入一个字符后会立即读取,不用按下回车键,这一点和 getche() 相同
。getch() 的特别之处是它没有回显,看不到输入的字符
。
所谓回显
,就是在控制台上显示出用户输入的字符
;没有回显,就不会显示用户输入的字符,就好像根本没有输入一样。
回显在大部分情况下是有必要的,它能够与用户及时交互,让用户清楚地看到自己输入的内容。但在某些特殊情况下,我们却不希望有回显,例如输入密码,有回显是非常危险的,容易被偷窥。
getch() 使用举例:
#include <stdio.h>
#include <conio.h>
int main()
{
char c = getch();
printf("c: %c\n", c);
return 0;
}
输入@
后,getch() 会立即读取完毕,接着继续执行 printf() 将字符输出。但是由于 getch() 没有回显,看不到输入的@
字符,所以控制台上最终显示的内容为c: @
。
5、gets() & puts() 函数
我们知道使⽤ scanf 函数,配合 "%s" 的输⼊格式,可以输⼊字符串
,使⽤ printf 函数,配合 "%s" 的输出格式,可以输出字符串
。
现在我们再学习⼀组函数:gets 和 puts。
char *gets(char *s) 函数从标准输⼊ stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。
int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到标准输出 stdout。
举例:
#include <stdio.h>
int main( )
{
char str[100];
printf( "Enter a value :");
gets(str);
printf( "\nYou entered: ");
puts(str);
return 0;
}
当上面的代码被编译和执行时,它会等待您输入一些文本,当您输入一个文本并按下回车键时,程序会继续并读取一整行直到该行结束,显示如下:
Enter a value :runoob
You entered: runoob
5.1、详细分析 gets:
#include <stdio.h>
int main()
{
char arr[10] = {0};
gets(arr);
printf("%s\n", arr);
return 0;
}
存储如图分析所示:
5.2、puts 与 printf 的区别:
#include <stdio.h>
int main()
{
char arr1[] = "abc";
char arr2[] = "def";
printf("%s", arr1);
printf("%s", arr2);
printf("\n"); //区分两次打印的效果
puts(arr1);
puts(arr2);
return 0;
}
我们从结果可以看出,使⽤ printf 函数打印字符串的时候,不会额外加上换行效果,但是 puts 在打印完字符串内容后主动换行。
5.3、使用 gets() 会报警告:
warning: this program uses gets(), which is unsafe.
gets() 不安全是因为未指定缓冲区大小。可以使用 fgets();
char* fgets(char *buf, int bufsize, FILE *stream);
- buf:字符型指针,指向用来存储所得数据的地址。
- bufsize:整形数据,指明缓冲区的大小,拷贝到 buf 地址的最大字符数量。
- stream:指明输入流的 FILE 对象的指针,stdin 可以作为参数,表示从标准输入读取。
返回值:成功,则函数返回 buf。
如果当尝试读取一个字符时遇到了文件结尾,则 eof 被置位(feof),如果还没有成功读入任何一个字符就遇到了文件结尾,那么就会返回 null,buff 中的内容保持不变。如果读取错误发生,那么 error indicator(ferror) 被置位,还是返回 null。
5.4、输出长文本【拓展】
当文本超出编辑窗口的宽度时,可以选择将文本换行,也可以选择将文本隐藏(可以在编辑器里面自行设置),但是不管哪种形式,在一个字符串里书写长文本不太美观。
#include <stdio.h>
int main()
{
puts("在 puts 函数中,可以将一个较长的字符串分割成几个较短的字符串,这样会使得长文本的格式更加整齐。");
return 0;
}
可以多写几个 puts 函数,如下:
#include <stdio.h>
int main()
{
puts("在 puts 函数中,");
puts("可以将一个较长的字符串分割成几个较短的字符串");
puts("这样会使得长文本的格式更加整齐。");
return 0;
}
在 puts 函数中,可以将一个较长的字符串分割成几个较短的字符串,这样会使得长文本的格式更加整齐。 注意:这只是形式上的分割,编译器在编译阶段会将它们合并为一个字符串,它们放在一块连续的内存中。 多个字符串并不一定非得换行,也可以将它们写在一行中,如下:
#include <stdio.h>
int main()
{
// 写在几行
puts(
"在 puts 函数中,"
"可以将一个较长的字符串分割成几个较短的字符串"
"这样会使得长文本的格式更加整齐。"
);
// 写在一行
puts("在 puts 函数中,""可以将一个较长的字符串分割成几个较短的字符串""这样会使得长文本的格式更加整齐。");
return 0;
}
6、所有输入输出函数总结
6.1、所有输入输出函数
(1)C 语言有多个函数可以从键盘获得用户输入
,它们分别是:
- scanf():是通用的输入函数,它可以读取多种类型的数据。
getchar()、getche()、getch()
:这三个函数都用于输入单个字符。gets()
:获取一行数据,并作为字符串处理。
(2)C 语言有多个函数可以从键盘获得用户输出
,它们分别是:
- printf():可以输出多种类型的数据。
putchar()、putche()、putch()
:这三个函数都用于输出单个字符。puts()
:输出一串数据。
6.2、所有输入函数总结
其中 scanf()、getchar()、gets() 是标准函数,适用于所有平台
;getche() 和 getch()
不是标准函数,只能用于 Windows
。
表格 还在加载中,请等待加载完成后再尝试复制
- scanf() 是通用的输入函数,它可以读取多种类型的数据。
- getchar()、getche() 和 getch() 是专用的字符输入函数,
在缓冲区和回显方面与 scanf() 有着不同的特性,是 scanf() 不能替代的。
- gets() 是专用的字符串输入函数,与 scanf() 相比,gets() 的主要优势是
可以读取含有空格的字符串
。
而且:
scanf() 可以一次性读取多份类型相同或者不同的数据,getchar()、getche()、getch() 和 gets() 每次只能读取一份特定类型的数据,不能一次性读取多份数据。
所有输出函数是类似的。
6.3、现象总结
#include <stdio.h>
int main()
{
int a,b,c;
a = getchar();
b = getche();
c = getch();
}
- 执行到 getchar() 函数时,光标闪动,等待输入字符:输入字符后无变化,需要按回车键, 按回车键后,getchar 读取了这个字符,并将其赋值给变量 a。
- 执行到 getche() 函数时,光标闪动,等待输入字符:输入字符后,不需按回车键,在输入后,getche 立即读入并赋值给 b。
- 执行到 getch() 函数时,光标闪动,等待输入字符:输入字符,并不能看到你输入的字符,屏幕仍是; 但在输入后瞬间,getch() 函数就读取并赋值给了 c。
《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
每日一更!
公众号、优快云等博客:小菜狗编程笔记
谢谢点赞关注哈!目前在飞书持续优化更新~
日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!