在计算机中,二进制数字与二进制数字串构成了各种数据。而在C语言中,字符与字符串涵盖了各种形式的字符数据。
字符
字符就是各种符号与各种文字,而在C语言中,由于字符就是数字的一种形式,所以我们可以通过数字运算循环,打印出这种“字符-数字"对应关系。
在程序设计中,验证观点的最好办法就是动手制作程序,下面我们将会向您展示 C语言 中的“字符-数字"对应关系。
C语言:使用 Ascil 字符集
/*
ascil.c
Print the ascil table
BeginnerC
*/
#include <stdio.h>
int main()
{
for (int i = 0; i < 256 ;i++)
{
printf("%d => %c \t", i, i);
if (i % 9 == 0)
{
printf("\n");
}
}
printf("\n");
return 0;
}
下面我们分析其中的知识点
- for 循环语句
在阅读过《入门:C语言中的逻辑与循环》之后,我们相信你一定已经了解到了 while 循环的使用方法。
事实上,C语言中的循环,殊途同归,只不过是同一样逻辑的不同表达形式。
for 循环与 while 循环的区别在于,for 循环为循环的初始化与每一次循环的收尾语句提供了位置 - % 运算
求余运算可以计算出每一次整数除法之后的余数
A % B 如果结果为 0,代表 A 可以被 B 整除 - printf 中的 %d %c
在 printf 函数中,%d 用于打印整数,%c 用于打印字符 - ‘\t’ 字符
制表符,反映到我们此处的程序,可以视作“8个空格"
而除了上面四条的知识点之外,最重要的莫过于整数与具体字符的对应关系,我们将这种关系称呼为“字符集"
(C语言使用 Ascil 字符集,转换关系由上面我们制作的程序所体现)
putchar & getchar 函数
在 C语言 中,putchar 函数可以用于打印字符,如您所见
/*
putchar.c
Use the putchar function
BeginnerC
*/
#include <stdio.h>
int main()
{
putchar('c');
return 0;
}
而 getchar 函数可以用来读取字符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vEgr04zN-1683077265704)(foruda.gitee.com/images/1677… “1672720001605.png”)]
/*
getchar.c
Use the getchar function
BeginnerC
*/
#include <stdio.h>
int main()
{
char c;
c = getchar();
putchar(c);
return 0;
}
字符的识别
C语言提供了有用的组件来帮助我们处理各种字符,这一组有用的组件包含在 ctype.h 标准库中。
比如,我们可以制作一个简单的字符识别小程序,它可以判断输入字符的类型。
/*
ctype.c
Judge the type of char
BeginnerC
*/
#include <ctype.h>
#include <stdio.h>
int main()
{
char c;
c = getchar();
if (isalpha(c))
{
printf("%c is a letter\n", c);
if (isupper(c))
{
printf("Upper Letter\n");
}
else if (islower(c))
{
printf("Lower Letter\n");
}
}
else if (isdigit(c))
{
printf("%c is a number\n", c);
}
else
{
printf("Unknow\n");
}
return 0;
}
字符的处理
在对字符的类型进行判断之外,我们还可以对字符本身进行转换。
ctype.h 也为我们提供了这方面的组件。
/*
alpha.c
Use toupper & tolower
BeginnerC
*/
#include <stdio.h>
#include <ctype.h>
int main()
{
char c;
c = getchar();
if (isalpha(c))
{
if (islower(c))
{
putchar(toupper(c));
}
else
{
putchar(tolower(c));
}
}
else
{
printf("Not a alpha.\n");
}
return 0;
}
拓展:中文的表示
早期的计算机,因为硬件条件与软件设计的限制,最初的字符集只能够用于表示字母与简单的符号,而对于其它形式的文字则无能为力。
而伴随着计算机硬件与软件的发展,有许多其它的字符集得以提出,用于展现其它的文字。
其中,GBK字库用于表示中文,为了兼容 Ascil 字符集合,GBK 字库使用 “单双字节变长编码,单字节编码完全兼容ASCII字符编码,而中文部分采用双字节编码。"
这种单双字节变长编码的做法,我们可以采用如下的形式进行验证:
/*
char_chinese.c
Test the chinese in C language
BeginnerC
*/
#include <stdio.h>
int main()
{
char c = '好';
printf("%d => %c\n", c, c);
return 0;
}
程序的执行没能符合我们的期待,原因显而易见,汉字占用两个字节,而一般的 Ascil 字符仅仅占用 1 个字节,因此自然不能用于表示汉字。
这种情况称之为“溢出",解决的办法在于拿出足够承载的空间。
在 C语言 中,标准库 wchar.h 提供了用于处理诸如汉字之类占用多字节的字符的函数与类型,我们称之为“宽字符函数库"
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QOlexdem-1683077265708)(foruda.gitee.com/images/1677… “1672716017927.png”)]
C语言参考材料 (由全球C/C++ 社区维护)上提供了与之有关的信息,在这里,由于宽字符相关的知识过于繁琐与复杂,我们选择不继续深入阐述。
值得注意的是,当下流行的字符集被称为 UTF-8 字符集,较之于 GBK,它具有更好的通用性。
字符串
字符串就是字符数组
由于字符串的本质就是字符的集合,从C语言的语法层面而言,是一个数组。
数组就是对相同类型变量的一个集合
如下面所展示
/*
string_array.c
Print the string
BeginnerC
*/
#include <stdio.h>
int main()
{
char string[] = "C Language";
for (int i = 0;i < sizeof(string);i++)
{
putchar(string[i]);
}
return 0;
}
字符数组就是数字流
在前文中我们发现,字符就是C语言中数字的另一种表示形式,因此对于字符串,我们当然也可以将他们视作为多个数字。
事实上,上面的程序可以改写为:
/*
string_array_int.c
Print the string
BeginnerC
*/
#include <stdio.h>
int main()
{
int string[] = {'C', ' ', 'L', 'a', 'n', 'g', 'u', 'a', 'g', 'e', '\0'};
for (int i = 0;i < sizeof(string) / sizeof(string[0]);i++)
{
putchar(string[i]);
}
return 0;
}
我们可以很明显地发现与第一个程序相比,这个程序变得明显地复杂,具体体现为如下:
- 我们没有使用 “C Language” 进行赋值
这是因为,int 类型数组终究代表整数类型数组,它并不是 C语言中内置用于处理字符串类型数据的类型,因此我们不能使用字符类型的语法糖进行处理(语法糖就是将某一项问题的解决用更简单的方式表示)
只能老老实实使用数组元素赋值的语法 - “C Language” 之外,多了一个 ‘\0’
在 C语言 中,所有的可以正常使用的字符串都需要以 ‘\0’ 字符作为收尾,换而言之,我们字符串的储存空间实际上“比我们见到的要大一点"
我们可以编写程序验证这一点 - for 循环语句的条件中,sizeof(string) 需要除 sizeof(string[0])
这是因为,在我们使用 char 数据类型的时候,每一个元素只占用一个字节,这就意味着,sizeof(string)是多少,就有多少个元素。
而第二个程序之中,因为 int 数据类型往往占用多个字节空间(往往是4个),如果我们还要使用之前的思路进行处理,势必出现问题。
所以我们必须要将 sizeof(string) 计算出的总储存空间,除以单个元素占用的储存空间,计算出元素的个数(元素个数 * 单个元素所用空间 = 总储存空间)
作为对 2 的验证,我们可以将 程序一 改写为如下
/*
string_array_ascil_code.c
Print the array ascil code
BeginnerC
*/
#include <stdio.h>
int main()
{
char string[] = "C Language";
for (int i = 0;i < sizeof(string);i++)
{
printf("%d => %c\n", string[i], string[i]);
}
return 0;
}
很明显发现,最后的元素就是 ‘\0’,也就是数字0
用数字流的思路,解决一些字符串问题
字符串的比较
我们可以用数字流的思路解决一些实际的问题,在这里,我们以字符串比较为案例
字符串的比较实际上就是对每一个元素所代表的数字进行比较,据此我们写出如下程序
/*
string_compare.c
Compare the string
BeginnerC
*/
#include <stdio.h>
int main()
{
char string_1[1024] = {};
char string_2[1024] = {};
int flag = 0;
scanf("%s", string_1);
scanf("%s", string_2);
for (int i = 0;i < 1024;i++)
{
if (string_1[i] != string_2[i])
{
flag = 1;
break;
}
}
if (flag)
{
printf("Not Equal\n");
}
else
{
printf("Equal\n");
}
return 0;
}
可以发现,尽管这个程序能够顺利地进行字符串的比较,但还是存在着许多缺陷,其中,最重要的就有两个
- 对字符串的比较,存在长度限制
- 忽略了参与比较的字符串可能存在比较的空间问题,容易造成溢出
因此,有比较对这一问题进行改进,由此我们提出如下方案
/*
string_compare_final.c
Compare the string
(Final Version)
BeginnerC
*/
#include <stdio.h>
int main()
{
char string_1[1024] = {};
char string_2[12] = {};
int flag = 0;
scanf("%s", string_1);
scanf("%s", string_2);
for (int i = 0;string_1[i] && string_2[i];i++)
{
if (string_1[i] != string_2[i])
{
flag = 1;
break;
}
}
if (flag)
{
printf("Not Equal\n");
}
else
{
printf("Equal\n");
}
return 0;
}
在这套方案之中,我们使用 字符串结束标志 作为结束的条件(&& 逻辑运算中,参与运算的两个变量中的一个为 0 时,结果为 0)
由此解决了长度的限制.
计算字符串的长度
用同样的方式,我们可以制作一个字符串长度统计程序
/*
string_length.c
Calc the length of string
BeginnerC
*/
#include <stdio.h>
int main()
{
char string[1024] = {};
int length = 0;
scanf("%s", string);
for (length = 0;string[length];length++)
;
printf("The length is %d\n", length);
return 0;
}
C语言中的字符串组件库
C语言 string.h 标准库提供了许多有用的字符串函数,我们可以使用他们解决各种有用的问题。
比如,字符串的比较与字符串的长度计算,就可以使用 strcmp 与 strlen 函数进行解决。