1 表示字符串和字符串IO
1 字符串是以空字符( \0 )结尾的 char 类型数组。
#include <stdio.h>
#define MSG "I am a symbolic string constant"
#define MAX_LENGTH 81
int main(void)
{
char words[MAX_LENGTH] = "I am a string in array.";
const char * pt1 = "Something is pointing at me.";
puts("Hear are some strings:");
puts(MSG);
puts(words);
puts(pt1);
words[8] = 'p';
puts(words);
return 0;
}
和 printf() 函数一样,puts() 函数也属于 stdio.h 系列的输入 / 输出函数。不同的是,puts() 函数只用来显示字符串,而且自动在显示的字符串末尾加上换行符。
值得注意的是,这条语句声明了 char 指针,那么字符串保存在哪里?
const char * pt1 = "Something is pointing at me.";
下面是调试过程:
变量值
内存值
可以看到,pt1 本质上只是一个char指针,而在内存空间保存了这整条的字符串,pt1 指向了字符串的首地址。
2 在程序中定义字符串
1 字符串常量
/* strptr.c -- 把字符串看作指针 */
#include <stdio.h>
int main(void)
{
/**
* %s 打印字符串
* %p 打印地址,如果"are"代表一个地址,printf()打印该字符串首字符的地址
* %c 解引用,打印字符串的首字符
*/
printf("%s %p %c\n", "We", "are", *"space farers");
return 0;
}
// 执行结果
We 00E37CD0 s
2 字符串数组和初始化
不指定,自动确定数组大小
字符串首地址与字符串数组
3 数组和指针
1 占用空间
非常重要的程序
程序结果分析:多次使用的相同字符串常量(包括宏定义),只使用一个存储位置
2 数组和指针的区别
数组名是常量,指针是变量,只有指针能进行自增、自减等操作
总结一下:数组的元素是变量,但数组名不是变量
3 指针指向字符串时,最好加 const 限定
为什么?因为编译器将多次使用的相同字符串,只使用一个存储位置。如果不加 const 限定,一旦使用指针修改了字符串,其他所有相同的字符串,全部被修改!!!
推荐用法:const char * pl = "hello world"
4 字符串数组
程序的执行结果和分析
两种字符串存储方式的区别:
3 字符串输入
1 分配空间
2 gets() 函数读取输入字符串
gets() 函数存在的问题:无法检查数组是否装的下输入行,可能会导致缓冲区溢出而不安全。
3 gets() 函数的替代品 fgets()
4 fgets() 函数的返回值:返回指向 char 的指针,如果一切顺利,该函数返回的地址与传入的第1个参数相同。但是,如果函数读到文件结尾,它将返回一个特殊的指针:空指针,一般用宏定义 NULL 标识。
从键盘输入的数据流中循环读取并打印
丢弃掉多余的超出长度的字符
#include <stdio.h>
#define STLEN 10
int main(void)
{
char words[STLEN];
int i, ch;
puts("Enter string(empty line to quit):");
// fgets() 从缓冲区读取9个字节
while (fgets(words, STLEN, stdin) != NULL && words[0] != '\n')
{
i = 0;
while (words[i] != '\n' && words[i] != '\0')
i++;
if (words[i] == '\n')
words[i] = '\0';
else // 如果word[i] == '\0',则执行下面的程序
while ((ch = getchar()) != '\n')
{
// putchar() 从缓冲区第10个字节开始继续读取
putchar(ch);
putchar('\n');
}
puts(words);
}
puts("Done");
return 0;
}
执行结果
5 空字符和空指针
6 scanf 函数
scanf 函数也能读取字符串。与gets() 函数类似,如果输入行过长,scanf 函数也会导致数据溢出。不过,在 %s 转换说明中使用字段宽度可以防止溢出。
4 字符串输出
1 puts() 函数
puts() 函数很容易使用,只需把字符串的地址作为参数传递给它即可。puts() 函数在字符串显示时,会自动在末尾添加换行符。puts() 函数如何知道在何处停止?该函数在遇到空字符 '\0' 时就自动停止,所以必须确保有空字符。
char name[100];
puts(name); // puts输出
2 fputs() 函数
char name[100];
fputs(name, stdout); // fputs输出
3 printf 函数
4 自定义输入输出函数
5 字符串函数
包含的头文件 string.h
1 strlen 函数 统计字符串的长度
下面的程序可以缩短字符串长度
#include <stdio.h>
#include <string.h>
void fit(char * pstring, unsigned int size);
int main(void)
{
char mesg[] = "12345_qwer hello, world!";
puts(mesg);
fit(mesg, 20);
puts(mesg);
fit(mesg, 5);
puts(mesg);
return 0;
}
void fit(char * pstring, unsigned int size)
{
if (strlen(pstring) > size)
pstring[size] = '\0';
}
执行结果
12345_qwer hello, world!
12345_qwer hello, wo
12345
2 strcat 函数 拼接字符串
获取整行输入字符串,并进行拼接的程序
考虑存储空间,毫无疑问,strcat() 函数也存在溢出的问题。当拼接后的字符串超过字符串1的内存空间时,就会发生溢出,此时可能会导致程序崩溃。
3 strncat() 函数
使用 strncat() 函数进行安全粘贴的程序
#include <stdio.h>
#include <string.h>
#define SIZE 30
#define BUGSIZE 13
char * s_gets(char * st, int n);
int main(void)
{
char flower[SIZE];
char addon[] = " smell like old shoes.";
char bug[BUGSIZE];
int avaliable;
puts("What's your favorite flower?");
s_gets(flower, SIZE); /* 读取字符,最多SIZE字节,然后清空缓冲区 */
if ((strlen(flower) + strlen(addon) + 1) <= SIZE)
strcat(flower, addon); /* 空间足够,进行粘贴 */
else
puts("Array don't have enough memory, strcat failed!");
puts(flower);
puts("What's your favorite bug?");
s_gets(bug, BUGSIZE);
avaliable = BUGSIZE - strlen(bug) - 1; /* 计算 bug 数组的剩余字节数 */
strncat(bug, addon, avaliable); /* 最多拷贝 avaliable 字节,防止溢出 */
puts(bug);
return 0;
}
char * s_gets(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;
}
执行结果
4 strcmp 函数 比较字符串
strcmp 函数是用来比较2个字符串的函数,如 srcmp(字符串1,字符串2),从第一个字符开始比较,如果到最后两个字符串完全相同,则strcmp()函数输出的值为0;若开始出现不同的字符,根据这个字符ASCII码进行比较,若字符串1的ASSCII值大于2,则输出值大于0;反之,输出值小于 0;
#include <stdio.h>
#include <string.h>
#define ANSWER "Grant"
#define SIZE 40
char * s_gets(char * st, int n);
int main(void)
{
char try[SIZE];
puts("Who is buried in Grant's tomb?");
s_gets(try, SIZE);
/* 读取键盘输入字符串,与 "Grant" 比较 */
while (strcmp(try, ANSWER) != 0)
{
puts("No, that's wrong. Try again.");
s_gets(try, SIZE);
}
puts("That's right!");
return 0;
}
char * s_gets(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;
}
执行结果
strcmp 函数的介绍
5 strncmp 函数:比较 n 个字符
6 strcpy() 函数 拷贝字符串
#include <stdio.h>
#include <string.h>
#define SIZE 40
#define LIM 5
char * s_gets(char * st, int n);
int main(void)
{
/* 字符串二维数组,保存输入中以 q 开头的单词 */
char qwords[LIM][SIZE];
char temp[SIZE];
int i = 0;
printf("Enter %d words beginning with q:\n", LIM);
while (i < LIM && s_gets(temp, SIZE))
{
if (temp[0] != 'q')
printf("%s doesn't beginning with q!\n", temp);
else
{
strcpy(qwords[i], temp);
i++;
}
}
puts("Here are the words accept:");
for (i = 0; i < LIM; i++)
puts(qwords[i]);
return 0;
}
char * s_gets(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;
}
void lower_letter(char * ptr)
{
const int diff = 'a' - 'A';
while (*ptr != '\0')
{
if ('A' <= *ptr && *ptr <= 'Z')
*ptr = *ptr + diff;
ptr++;
}
}
strcpy() 函数拷贝程序执行结果
strcpy() 函数的其他属性
和之前一样,strcpy 函数也存在数据溢出的风险。
7 strncpy() 函数 拷贝n个字节
8 strchr() 函数
char *strchr(const char *s, int c)
功能: 查找字符串s中首次出现c字符的位置
说明: 返回首次出现c的位置的指针,返回的地址是被查找的字符串指针开始的第一个与c相同字符的指针,若s中不存在c则返回NULL。
返回值: 成功返回要查找的字符第一次出现的位置,否则返回NULL。
9 sprintf 函数
6 命令行参数
下面是获取输入参数的程序:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
printf("We get %d parameters.\n", argc);
for (i = 0; i <= argc; i++)
printf("argv[%d]: %s\n", i, argv[i]);
return 0;
}
程序执行结果如下
参考链接:
https://blog.csdn.net/dingyc_ee/article/details/103023888