C语言--字符串和字符串函数(一)

表示字符串和字符串I/O

字符串是以空字符(\0)结尾的char类型数组。C提供了许多用于处理字符串的函数。
表示字符串的几种方式:

#include<stdio.h>
#define STR "I am a symbolic string constant."
#define SIZE 50
int main(void)
{
	char words[SIZE] = "I am a string in an array.";
	const char* pt1 = "Something is pointing at me.";
	puts("Here are some strings.");
	puts(STR);
	puts(words);
	puts(pt1);
	
	return 0;
}

运行结果:
在这里插入图片描述
puts()函数也属于stdio.h系列中的输入输出函数。puts()函数只显示字符串,而且自动在显示的字符串末尾加上换行符

在程序中定义字符串

字符串字面量(字符串常量)

用双引号括起来的内容称为字符串字面量,也叫字符串常量
ANSI C标准起,如果字符串字面量之间没有间隔,或者空白字符分隔,C会将其视为字符串字面量。
示例:

char greeting[40] = "hello, ""nice to meet you!";
等价于
char greeting[40] = "Hello, nice to meet you!";

字符串常量属于静态存储类别,这说明如果函数中使用字符串常量,该字符串只会被存储一次,在整个程序的生命期内存在。
用双引号括起来的内容被视为指向该字符串存储位置的指针。

字符串数组和初始化

定义字符串数组时,必须让编译器知道需要多少空间。
一种方法是用足够的空间的数组存储字符串。示例:

const char str[50] = "This is a string.";

在指定数组大小时,要确保数组的元素个数至少比字符串长度多1,是为了容纳空字符。所有未被使用的元素都被自动初始化为0。
示例:

const char str[10] = "string.";

在这里插入图片描述
(画的有点丑。。凑合看)

省略数组初始化声明中的大小,编译器会自动计算数组大小:

#include<stdio.h>
int main()
{
	const char str[] = "I only hope that I will one day "
		"deserve what you have done for me.";

	printf("The size of str is %zd.\n", sizeof(str));
	return 0;
}

运行结果:
在这里插入图片描述

字符数组名和其他数组名一样,是该数组首元素的地址。
示例:若有

const char str[10] = "String";

则下面表达式都为真:

str == &str[0] ;
*str == 'S';
*(str + 1) == str[1] == 't';

还可以使用指针表示法创建字符串:

const char* ptr = "Something is pointing at me.";

但和数组的声明不完全一样。

数组和指针

通常,字符串都作为可执行文件的一部分存储在数据段中。字符串存储在静态存储区中。
程序示例:

#include<stdio.h>
#define STR "I am a computer."
int main()
{
	//指针形式
	const char* ptr = STR;
	//数组形式
	const char str[] = STR;
	printf("address of STR: %p\n", STR);
	printf("address of ptr: %p\n", ptr);
	printf("address of str: %p\n", str);
	return 0;
}

输出结果:
在这里插入图片描述
可以看出宏定义的字符串地址和指针指向的地址相同,原因是字符串存储在内存中的r data区域,而数组表示法的地址和他们不同,原因是声明数组是在栈区中开辟空间,再把字符串拷贝进去,所以地址不一样。

数组和指针区别

char str1[] = "I am a string.";
const char* ptr = "I am a string.";

主要区别:
1, 数组名str1是常量,而指针名ptr是变量。
2,两者都可以使用数组表示法:

putchar(str1[1]);
putchar(ptr[1]);

3,两者都能进行指针加法操作:

putchar(*(str1 + 1));
putchar(*(ptr + 1));

但是, 只有指针表示法可以进行递增操作:

putchar(*(ptr++));

若想让两者统一:

ptr = str1;	//ptr指向str1
str1 = ptr;	//非法构造,错误

其实还是左值和右值问题,左值一般是可被赋值的变量,右值是常量。

字符串数组

字符串数组经常使用两种表示方法:指向字符串的指针数组和char类型数组的数组。
程序示例:

#include<stdio.h>
#define SLEN 40
#define LIM 5
int main(void)
{
	const char* mytalent[LIM] = {
		"Adding number swiftly",
		"Multiplying accurately",
		"Stashing data",
		"Following instructions to the letter",
		"understanding the C language"
	};
	char yourtalent[LIM][SLEN] = {
		"Walking in a straight line",
		"Sleeping", "Watching television",
		"Mailing letters", "Reading email"
	};
	int i = 0;

	printf("%-36s %-25s\n", "Mytalent", "Yourtalent");
	for (i = 0; i < LIM; ++i)
	{
		printf("%-36s %-25s\n", mytalent[i], yourtalent[i]);
	}
	printf("\nsizeof mytalent: %zd, sizeof yourtalent: %zd\n",
		sizeof(mytalent), sizeof(yourtalent));

	return 0;
}

运行结果:

在这里插入图片描述

mytalent数组只占用了20字节,因为数组里面的每个元素都是指针,每个占4字节。
虽然指针数组占用空间少且更高效,但数组里的这些指针指向的字符串字面量不能更改。

字符串输入

如果想把一个字符串读入程序,首先必须预留存储该字符串的空间,然后用输入函数获取该字符串。

分配空间

最简单的方法是,在声明时指明数组大小且空间足够:

char str[40] = ”I am a string.";

gets()函数

该函数用于显示字符串,并在末尾添加换行符。常与puts()配对使用。
如果输入的字符串过长,会导致缓冲区溢出。。

在C11标准中已经不再使用它,比如 vs2019不支持gets()函数。

gets()的替代品

过去常用fgets()代替,C11标准中新增的gets_s()也可以代替

fgets()函数

它通过第二个参数限制读入的字符数来解决溢出的问题。
格式:

fgets(words, STLEN, stdin);

和gets()的区别有:

  • fgets()函数的第二个参数指明了读入字符的最大数量。如果参数为n,则读入n - 1个字符,或者读到第一个换行符为止。
  • 如果fgets()读到一个换行符, 会把它存储在字符串中,gets()会直接丢弃。
  • fgets()函数的第三个参数指明要读入的文件。如果读入从键盘输入的数据,则以stdin(标准输入)作为参数,该标识符定义在stdio.h中。

gets_s()函数

格式:

gets_s(words, STLEN);

和fgets()区别:

  • 只从标准输入中读取数据,所以不需要第三个参数。
  • 遇到换行符会丢弃它而不是存储它。
  • 如果gets_s()函数读到最大字符数都没有读到换行符,会执行以下操作:首先把目标数组中的首字符设置为空字符,读取并丢弃随后的输入直至读到换行符或文件结尾,然后返回空指针。

s_gets()函数

读取整行输入并用空字符代替换行符。
或者读取一部分输入,并丢弃其余部分。

char* s_gets(char* st, int n)
{
	char* ret_val;
	int i;

	ret_val = fgets(st, n, stdin);
	if (ret_val)	//ret-val != nullptr
	{
		while (st[i] != '\n' && st[i] != '\0')
		{
			++i;
		}
		if (st[i] == '\n')
			st[i] == '\0';
		else
			while (getchar() != '\n')
				continue;
	}
	return ret_val;
}

scanf()函数

scanf()更像是“获取单词”, 因为它从第一个非空白字符作为字符串的开始,若使用%s转换说明,以下一个空白字符(空行,空格,制表符或换行符)作为字符串的结束。
示例:

#include<stdio.h>
#include<string.h>
int main(void)
{
	char name[20];

	printf("Please input name:\n");
	scanf_s("%s", name, 20);
	
	printf("%s\n", name);

	return 0;
}

运行结果:
在这里插入图片描述

可以看出,scanf()只读取了空格前面的一个单词。

字符串输出

C有三个标准库函数来打印字符串:

  • puts()
  • fputs()
  • printf()

puts()函数

使用时只需把字符串的地址传递给它。

const char* str = "I am a string.";

puts(str);

fputs()函数

fputs()是puts()函数针对文件定制的版本,区别如下:

  • fputs()函数的第二个参数指明要写入数据的文件。如果要打印在显示器上,用stdout作为该参数。
  • 与puts()不同,fputs()函数不会在输出的末尾添加换行符。

注意
gets()丢弃输入中的换行符,而puts()在输出中添加换行符。
fgets()保留输入中的换行符,fputs()不在输出中添加换行符。

printf()函数

printf()不会自动在每个字符串末尾加上换行符,因此必须在参数中指明在哪里使用换行符。示例:

printf("%s\n", str);
等价于
puts(str);

自定义输入输出函数

假设需要一个类似puts()但不会自动添加换行符的函数。

#include<stdio.h>
void put1(const char* string)
{
	while (*string != '\0')
		putchar(*string++);
}

假设要设计一个类似puts()的函数,而且该函数还给出待打印字符的个数。

#include<stdio.h>
int put2(const char* string)
{
	int count = 0;
	while (*string != '\0')
	{
		putchar(*string++);
		count++;
	}
	putchar('\n');	//不统计换行符

	return count;
}

示例:

#include<stdio.h>
void put1(const char* string)
{
	while (*string != '\0')
		putchar(*string++);
}

int put2(const char* string)
{
	int count = 0;
	while (*string != '\0')
	{
		putchar(*string++);
		count++;
	}
	putchar('\n');	//不统计换行符

	return count;
}

int main(void)
{
	put1("I only hope that I will oneday");
	put1("deserve what you have done for me.\n");

	printf("This string has %d characters.\n",
		put2("You like an angel."));

	return 0;
}

运行结果:
在这里插入图片描述

。。。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值