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