《小菜狗 C 语言入门 + 进阶笔记》(25)字符与字符串【常用】

《小菜狗 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();
}
  1. 执行到 getchar() 函数时,光标闪动,等待输入字符:输入字符后无变化,需要按回车键, 按回车键后,getchar 读取了这个字符,并将其赋值给变量 a。
  2. 执行到 getche() 函数时,光标闪动,等待输入字符:输入字符后,不需按回车键,在输入后,getche 立即读入并赋值给 b。
  3. 执行到 getch() 函数时,光标闪动,等待输入字符:输入字符,并不能看到你输入的字符,屏幕仍是; 但在输入后瞬间,getch() 函数就读取并赋值给了 c。

《小菜狗 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、付费专栏及课程。

余额充值