前言:
考虑到之前在专栏中讲字符串的时候有些知识点没有详细地讲解,所以本篇是对字符串相关的知识点的补充篇!例如 %s 输出左对齐右对齐,限制格数等知识,在那个专栏的部分代码中出现了,但只是用注释简单的提了下,并没有详细地讲,所以本篇将针对部分遗漏的知识点进行补充和巩固。本篇通过C语言教材《The C Programming Language》作为参考进行讲解。
0x00 字符串概念(String concepts)
① 字符串是连续排列的字符。
② 因为字符串的长度是可变的,所以体现方法也很多样。
📚 C语言中使用斜杠0来表示一个字符串的结束。
0x01 斜杠0(The String Delimiter)
❓ 为什么需要斜杠0?
① C语言中没有字符串(String)数据类型。
② C语言使用字符数组(Char array)来保存字符串。
为了能够更好地区分 String 和 Char Array ,我们需要斜杠0。
0x02 字符串常数(String Literals & String Constant)
📚 字串串常数是由大引号括起来的字符序列(character's sequence)
“C is a high-level language”
“Hello”
字符串常数是指针
如果使用字符串常数,C将自动生成character数组并储存,并返还该数组的起始地址。
💬 所以,可以将字符串上的数字作为数组名:
#include <stdio.h>
int main(void) {
printf("%c\n", "Hello"[1]);
return 0;
}
📚 字符常数是由单引号标出的单个字符
'a', 'b', 'c', '1', '2', '3'
'\0', '\n'
根据ASCII码体系分类,对应 0~255:比如 'A' = 65,'\0' = 0
因为是整数,所以可以进行字符常数 + 整数的整数运算
当然,可以用在各种地方:
if( ‘A’ <= c && c <= ‘Z’ )
0x03 存储(Storing Strings and Characters)
📚 如下图所示,字符串和字符存储在内存中是有差异的:
因此,储存字符串常数时,需要考虑到存放斜杠0的空间。
举个例子,为了保存 “Hello” 这个字,5个字符 + 斜杠0,总共需要6个空间。
0x04 字符串初始化的四种方法
① 给定数组大小
② 不给定数组大小
③ 使用指针
④ 先声明再用单引号逐个输入
💬 字符串初始化时,使用指针和数组的差异:
char *p = "abcdef";
char s[] = "abcdef";
p 作为指针变量有额外的存储空间,但是 s 只表示数组的起始地址,它并不是一个变量。
0x05 字符串和指针(Strings and Pointers)
字符串存储在数组中,因为数组名是指针,所以可以利用它输出下列字符串:
#include <stdio.h>
int main(void) {
char greeting[] = "Hello";
char* ptr;
ptr = greeting;
while(*ptr != '\0') {
printf("%c", *ptr);
ptr++;
}
printf("\n");
return 0;
}
📚 %s 可以从指针的起始地点开始输出到斜杠零停止
💬 我们还可以这么干:
#include <stdio.h>
int main(void) {
char s[] = {'a', 'b', 'c', 'd', 'e', '\0'};
printf("从头开始输出: %s\n", s);
printf("跳过2位后开始输出: %s\n", s + 2);
return 0;
}
🚩 运行结果:
从头开始输出:abcde
跳过2位后开始输出:cde
0x06 字符串输入输出函数 String input/output function
利用scanf 和printf ,可以进行字符串的输入输出。
💬 scanf:
scanf("%s", month);
💬 输入长度为9的字符串并保存到数组中:
char month[10];
scanf("%9s", month); // 限制
📌 注意事项:
用 %s 接收时无法接收到 blank(“”)、tab(“\ t”)等。
不满足条件的地方和它后面的部分都会被无视。
💬 利用 scanf 函数输入字符串的示例程序
#include <stdio.h>
int main(void) {
char str[10];
char *p;
printf("输入一个字符串: ");
scanf("%9s", str); //限制最多接收9个
p = str;
while(*p != '\0') { //利用while让字符串逐字符输出
printf("%c", *p);
p++;
}
printf("\n");
return 0;
}
🚩 运行测试:
最多接收9个,所以结果为 123456789
证明 %s ,空格会阻断。
📚 使用 print 函数打印字符串
和 scanf 一样,使用 %s 输出字符串
只输出 \0 之前的内容,所以如果字符串中间有 \0,则后面的内容不会被输出。
💬 利用 printf 函数输出字符串的示例程序:
#include <stdio.h>
int main(void) {
printf("|%30s|\n", "This is the string");
printf("|%-30s|\n", "This is the string");
printf("|%-15.14s|\n", "12345678901234567890");
printf("|%15.14s|\n", "12345678901234567890");
return 0;
}
🚩 运行结果:
0x07 gets / fgets 函数
它们和根据格式输入的 scanf、fscanf 等不同,gets 和 fgets 是没有格式的读入行的函数。
📚 gets 函数的原型:
char* gets(char* strPtr);
成功:返回 strPtr 的地址
失败:返回 NULL
从键盘那接收一行,保存到 strptr 中。( \n 之前算作为一行,\n 被置换为 \0”保存)
📌 注意事项:如果其长度比 strPtr 的长度长,那么 strPtr 后面的内存就会被侵犯,要注意 Segmentation fault 的发生!
📚 fgets 函数的原型:
char* fgets(char* strPtr, int size, FILE *fp);
成功:返回 strPtr 的地址
失败,触尾部(EOF):NULL
从文件指针 FILE* 开始,fp 那里开始读取一行并保存到 strptr 中。
最大读取个数为 size-1 个。( \n 之前算作为一行,\n 被置换为 \0”保存)。
在文件指针 FILE* 上设置 stdin,就可以从键盘上输入了。通常来说,与 gets 函数 相比我们更建议使用 fgets 函数。
💬 fgets 用法演示:
#include <stdio.h>
int main(void) {
char str[81];
printf("请输入一个字符串: ");
fgets(str, sizeof(str), stdin);
printf("你输入的字符串是:\n\t%s", str);
return 0;
}
🚩 运行结果:
0x09 puts / fputs 函数
不同于按格式输出 printf 和 fprinf 函数 ,puts 和 fputs 是不格式化直接打印一行的函数。
📚 puts 函数的原型:
int puts (const char *strPtr);
成功:返回打印的字符数(包括被置换成\0的\n)
失败:EOF(-1)
• 将 strPtr 的字符串作为一行输出到屏幕上。
📌 注意事项:
① 由于 \0 被 \n 替换,如果字符串末尾有 \n ,换行会出现两次。
② 由于只输出 \0,所以如果字符串中间有 \0,则忽略后面的部分。
📚 fputs 函数的原型:
int fputs (const char *strPtr, FILE *fp);
成功:返回1
失败:返回EOF(-1)
将 strPtr 的字符串录入到文件指针 fp 中。
strPtr 必须以 \0 结尾,并且不会输出空字符。
由于只输出 \0,如果字符串中间有 \0 ,则会忽略后面的内容。
如果将 stdout 提供给文件指针 fp,就可以将其输出到屏幕上。
gets 函数与 fgets 函数有着巨大的差异。
💬 fputs 用法演示:
#include <stdio.h>
int main(void) {
char str[] = "True Self Is Without From.";
char* pStr = str; //指定字符串起始位置
fputs(pStr, stdout); //从头到尾输出
fputs("\n", stdout);
fputs(pStr + 13, stdout); //从13个那开始输出
return 0;
}
🚩 代码演示:
💬 fgets / fputs 用法演示
#include <stdio.h>
int main(void) {
char str[81];
while(fgets(str, sizeof(str), stdin) != NULL) {
if('A' <= str[0] && str[0] <= 'Z')
fputs(str, stdout);
}
return 0;
}
参考文献:
Computer Science: A Structured Programming Approach Using C – BEHROUZ. FOROUZAN, RICHARD F.GILBERG
The C Programming Language - Brian W. Kernighan, Dennis M. Ritchie, Practical C Programming - Steve Oualline
本篇完。