C语言-字符串的定义及使用

Posted 穿迷彩服的鲨鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言-字符串的定义及使用相关的知识,希望对你有一定的参考价值。

字符串的定义及使用


前言

字符串的存储方式有字符数组和字符指针。

因为字符串是由多个字符组成的序列,所以要想存储一个字符串,可以先把它拆成一个个字符,然后分别对这些字符进行存储,即通过字符数组存储。字符数组是一个数组,且是存储字符的数组,该数组中一个元素存放字符串的一个字符。


一、字符数组的定义

1

因为字符数组首先是一个数组,所以前面讲的数组内容通通都适用。其次它是存放字符的数组,即数组的类型是 char 型。比如:

char name[10];

表示定义了 10 字节的连续内存空间。

  1. 如果字符串的长度大于 10,那么就存在语法错误。这里需要注意的是,这里指的“字符串的长度”包括最后的 ‘\\0’。也就是说,虽然系统会自动在字符串的结尾加 ‘\\0’,但它不会自动为 ‘\\0’ 开辟内存空间。所以在定义数组长度的时候一定要考虑 ‘\\0’。

  2. 如果字符串的长度小于数组的长度,则只将字符串中的字符赋给数组中前面的元素,剩下的内存空间系统会自动用 \\0’ 填充。

2

我们在用C语言编写程序时,经常会遇到使用字符串数组的情况,这种数组的特点是, 数组中的每个元素都是一个字符串,但每个字符串的长度却不相同。如果你使用C++语言进行编程的话,实现起来相对比较简单,只需直接选择标准模板库的字符串string类,在代码中定义该类的一个数组即可实现。现在的问题是,在纯C语言中如何定义这样的一个字符串数组呢?

如对于下面的一个字符串数组:

str = 
	"I love C.",
	"I love C++.",
	"I love JAVA.",
	"I love Python.",
	"I love LabVIEW."

下面给出C语言中的两种定义方法。
方法1:定义一个char类型的二维数组

这种方法是通过定义一个char类型的二维数组实现,通过二维数组的行索引可得到数组中的每个字符串,列的大小限定了每个字符串所能包含的最大字符个数,所以采用这种定义方式时,列的大小必须不能小于数组所有字符串的最大长度。如对于上面的数组,C语言的定义代码如下:

char str[5][20] = 
	"I love C.",
	"I love C++.",
	"I love JAVA.",
	"I love Python.",
	"I love LabVIEW."

在取该数组的每个字符串时,直接对行索引即可。

方法2:定义一个指向char类型的指针数组

这种方法是通过定义一个指向char类型的指针数组实现,数组中的每个元素都是一个指针,通过该指针可得到数组中的每个字符串。如对于上面的数组,C语言的定义代码如下:

char *str[5] = 
	"I love C.",
	"I love C++.",
	"I love JAVA.",
	"I love Python.",
	"I love LabVIEW."

两种方法对比

上面的两种方法都可以实现我们的目的,但在内存的占用上两种方法不同。第1种方法定义了一个5行20列的二维数组,即每个字符串所占的字节长度都为20个,所以共需要占用100个字节,而第2种方法是定义的指针数组,每个指针指向的字符串占用的字节长度是其实际长度,所以其总的长度肯定小于100个字节。综合来讲,第1种方法相对于第2种方法,造成了存储空间的浪费情况。

二、字符数组的初始化

字符数组的初始化与数组的初始化一样,要么定义时初始化,要么定义后初始化。下面写一个程序来说明这个问题:

代码如下(示例):

# include <stdio.h>

int main()

    char a[10];
    a[0] = 'i'; a[1] = ' '; a[2] = 'l'; a[3] = 'o'; a[4] = 'v'; 
	//空格字符的单引号内一定要敲空格
    a[5] = 'e'; a[6] = ' '; a[7] = 'y'; a[8] = 'o'; a[9] = 'u'; 
    a[10] = '\\0'; 
    
    char b[10];
    b[0] = 'i'; b[1] = ' '; b[2] = 'm'; b[3] = 'i'; b[4] = 's'; 
    b[5] = 's'; b[6] = ' '; b[7] = 'y'; b[8] = 'o'; b[9] = 'u'; 
    
    char c[] = "i believe you";
    
    char d[] = 'i', ' ', 'l', 'i', 'k', 'e', ' ', 'y', 'o', 'u','\\0'; 

    char e[] = 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'; 

    char f[] = "不是我抄你的,就是你抄我的!";
    
    char g[10] = "";
    
    printf("a = %s\\n", a);  //输出字符串用%s, 输出参数必须写数组名
    printf("b = %s\\n", b);
    printf("c = %s\\n", c);
    printf("d = %s\\n", d);
    printf("e = %s\\n", e);
    printf("f = %s\\n", f);
    printf("g = %s\\n", g);
    return 0;
    
    /*
    输出结果是:
	a = i love you
	b = i miss you琉i love you
	c = i believe you
	d = i like you
	e = Hello World繇 like you
	f = 不是我抄你的,就是你抄我的!
	g =
	*/

1.先定义后初始化

	char a[10];
    a[0] = 'i'; a[1] = ' '; a[2] = 'l'; a[3] = 'o'; a[4] = 'v'; 
	//空格字符的单引号内一定要敲空格
    a[5] = 'e'; a[6] = ' '; a[7] = 'y'; a[8] = 'o'; a[9] = 'u'; 
    a[10] = '\\0'; 

数组 a 是先定义后初始化。一方面与以前讲的数值型数组一样,先定义后初始化必须一个一个地进行赋值,不能整体赋值;另一方面与以前讲的数值型数组又不一样,对于字符串,先定义后初始化也可以整体赋值,但是要调用 strcpy 函数,这点稍后再讲。

总之上面这个程序中给数组 a 一个一个进行初始化的方式很麻烦。而且这样写需要注意:前面讲过系统会在字符串的最后自动添加结束标志符 ‘\\0’,但是当一个一个赋值时,系统不会自动添加 ‘\\0’,必须手动添加。如果忘记添加,虽然语法上没有错误,但是程序将无法达到我们想要的功能。数组 b 就是这样的例子。

此外,空格字符必须要在单引号内“敲”一个空格,不能什么都不“敲”,什么都不“敲”就是语法错误。也不能多“敲”,因为一个单引号内只能放一个字符,“敲”多个空格就是多个字符了。

 	char b[10];
    b[0] = 'i'; b[1] = ' '; b[2] = 'm'; b[3] = 'i'; b[4] = 's'; 
    b[5] = 's'; b[6] = ' '; b[7] = 'y'; b[8] = 'o'; b[9] = 'u'; 

数组b就是最后没有手动添加 ‘\\0’ 的例子。程序是希望数组 b 输出“i miss you”,但输出结果是“i miss you錌i love you”。原因就是系统没有在最后添加’\\0’。

虽然程序中对数组 b 的长度进行了限制,即长度为 10,但是由于内存单元是连续的,对于字符串,系统只要没有遇到 ‘\\0’,就会认为该字符串还没有结束,就会一直往后找,直到遇到 ‘\\0’ 为止。被找过的内存单元都会输出,从而超出定义的 10 字节。

2.定义时初始化

char c[] = "i believe you";

数组 c 是定义时初始化。定义时初始化可以整体赋值。整体赋值有一个明显的优点——方便。定义时初始化可以不用指定数组的长度,而先定义后初始化则必须要指定数组的长度,如数组 a 和数组 b。不用指定数组长度有一个好处:不用人为确定需要多少字节的内存空间,系统会根据初始化的内容自动分配数量正好的内存空间。而且对于数组 c 的写法系统会自动在最后添加结束标志符 ‘\\0’,不需要人为添加。

char d[] = 'i', ' ', 'l', 'i', 'k', 'e', ' ', 'y', 'o', 'u','\\0'; 

数组 d 也是定义时初始化,但它既属于整体赋值,也属于一个一个赋值。说它是整体赋值是因为不用写 d[0]、d[1]…而说它是一个一个赋值是因为它把整个句子分成了一个一个的字符。还是数组 c 的写法比较方便,而且对于数组d的写法系统也不会自动在最后添加结束标志符 ‘\\0’,必须人为添加。如果忘记添加就会出现与数组 b 同样的错误。从数组 e 的输出结果可以看出这一点。

char f[] = "不是我抄你的,就是你抄我的!";

数组 f 是存储汉字,汉字不能像数组 a 或数组 d 那样分开一个一个赋值。因为一个汉字占 2 字节,若分开赋值,由于一个单引号内只能放一个字符,即一字节,所以将占 2 字节的汉字放进去当然就出错了。因此如果用字符数组存储汉字的话必须整体赋值,即要么定义时初始化,要么调用 strcpy 函数。

char g[10] = "";

数组 g 初始化为一对双引号,表示该字符数组中 10 个元素的内容都为 ‘\\0’。下面写一个程序验证一下:

# include <stdio.h>
int main()

    char str[3] = "";
    str[2] = 'a';
    printf("str = %s\\n", str);
    return 0;

输出结果是:
str =

程序中定义了一个长度为 3 的字符数组,然后给第三个元素赋值为 ‘a’,然后将整个字符数组输出。但是输出结果什么都没有,原因就是其直接初始化为一对双引号,此时字符数组中所有元素都是 ‘\\0’。所以虽然第三个元素为 ‘a’,但因为第一个元素为 ‘\\0’,而 ‘\\0’ 是字符串的结束标志符,所以无法输出。

需要注意的是,使用此种初始化方式时一定要指定数组的长度,否则默认数组长度为 1。

总结,字符数组与前面讲的数值数组有一个很大的区别,即字符数组可以通过“%s”一次性全部输出,而数值数组只能逐个输出每个元素。

三、怎样引用字符数组中的元素

1.输出一个已知的字符串

#include<stdio.h>

int main()

	char c[] =  'I',' ','C','o','m','e',' ','F','r','o','m',' ','N','Y','I','S','T','\\0' ;
	/*法一*/
	for (int i = 0; i < 17; i++)
	
		printf("%c", c[i]);
	
	
	printf("\\n");
	/*法二*/
	printf("%s",c);
	return 0;

2.输出一个菱形

#include<stdio.h>

int main()

	char diamond[][5] =  ' ',' ','*',' ','*',' ','*','*',' ',' ',' ','*',
	' ','*',' ','*',' ',' ','*' ;
	int i, j;
	for (int i = 0; i < 5; i++)
	
		for (int j = 0; j < 5; j++)
		
			printf("%c", diamond[i][j]);
		
		printf("\\n");
	
	return 0;

3.连续字符–力扣题目

给你一个字符串 s ,字符串的「能量」定义为:只包含一种字符的最长非空子字符串的长度。
请你返回字符串的能量。

示例 1:
输入:s = “leetcode”
输出:2
解释:子字符串 “ee” 长度为 2 ,只包含字符 ‘e’ 。

示例 2:
输入:s = “abbcccddddeeeeedcba”
输出:5
解释:子字符串 “eeeee” 长度为 5 ,只包含字符 ‘e’ 。

示例 3:
输入:s = “triplepillooooow”
输出:5

示例 4:
输入:s = “hooraaaaaaaaaaay”
输出:11

示例 5:
输入:s = “tourist”
输出:1

#include<stdio.h>
#include<string.h>

int maxPower(char *s) 

	int i;
	int start;
	int max_len = 1;
	int temp_len = 1;

	start = 0;
	for (i = 1; i < strlen(s); i++) 
	
		if (s[i] == s[start])
		
			temp_len++;
		 
		else 
		
			start = i;
			if (temp_len > max_len) 
			
				max_len = temp_len;
			
			temp_len = 1;
		
	

	// 最后一句很关键,把最后start直到末尾算出的temp_len和max_len比较一下
	// 例如“eettt”,计算出的max_len为2,但最后start直到末尾算出的temp_len为3
	return max_len > temp_len ? max_len : temp_len;



int main() 

	char str[]="aaaabbbeeeeeee";
	int len = maxPower(str);
	printf("%d",len);
	return 0;

4.截断句子—力扣题目

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)。

例如,“Hello World”、“HELLO” 和 “hello world hello world” 都是句子。
给你一个句子 s​​​​​​ 和一个整数 k​​​​​​ ,请你将 s​​ 截断 ​,​​​使截断后的句子仅含 前 k​​​​​​ 个单词。返回 截断 s​​​​​​ 后得到的句子。

示例 1:
输入:s = “Hello how are you Contestant”, k = 4
输出:“Hello how are you”
解释:
s 中的单词为 [“Hello”, “how” “are”, “you”, “Contestant”]
前 4 个单词为 [“Hello”, “how”, “are”, “you”]
因此,应当返回 “Hello how are you”

示例 2:
输入:s = “What is the solution to this problem”, k = 4
输出:“What is the solution”
解释:
s 中的单词为 [“What”, “is” “the”, “solution”, “to”, “this”, “problem”]
前 4 个单词为 [“What”, “is”, “the”, “solution”]
因此,应当返回 “What is the solution”

示例 3:
输入:s = “chopper is not a tanuki”, k = 5
输出:“chopper is not a tanuki”

#include<stdio.h>
#include<string.h>

char * truncateSentence(char * s, int k) 

	int len = strlen(s);
	int cnt = 0;
	int i;
	for (i = 0; i < len; i++) 
	
		if (s[i] == ' ' && (++cnt == k)) 
		 /* 空格够了, 就添加结束符 */
			s[i] = '\\0';
			break;
		
	
	return s;


int main()

	char str[]="aaa abb bee ee eee";
	char *len = truncateSentence(str,3);
	printf("%s",len);
	return 0;

总结

以上是关于C语言-字符串的定义及使用的主要内容,如果未能解决你的问题,请参考以下文章

C语言:统计输入的一行英文句子中的字母及单词个数,带注解!

[C] 语言字符串文件及内存分配函数

仅在字符串末尾匹配整个句子

用C语言编辑,输入一个英文句子,删除句子的前导空格和后导空格,并使单词之间只有一个空格。

(C语言编程)输入一个英文句子,将每个英文单词的头字母变为大写,单词之间用空格隔开

翻转句子中单词的顺序 C语言