c primer plus 專題11:字符串

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章