C語言學習筆記(六)字元串
- 一、字元串
-
- (1)字元串
-
- 1.1 字元數組
- 1.2 字元串
- 1.3 字元串變量
- 1.4 字元串常量
- 1.5 總結
- (2)字元串變量
-
- 2.1字元串常量
- 2.2 指針還是數組?- char* str="Hello";
- 2.3 char*是字元串?
- (3)字元串輸入輸出
-
- 3.1字元串指派?
- 3.2安全的輸入
- 3.3常見錯誤
- (4)字元串數組以及程式參數
-
- 4.1 字元串數組
- 4.2 程式參數
- 二、字元串函數
-
- (1)單字元輸入輸出
-
- 1.1 putchar
- 1.2 getchar
- 1.3 測試代碼
- (2)字元串函數strlen
-
- 2.1 函數原型
- 2.2 測試代碼
- (3)字元串函數strcmp
-
- 3.1 函數原型
- 3.2 測試代碼
- (4)字元串函數strcpy
-
- 4.1 函數原型
- 4.2 測試代碼
- (5)字元串函數strcat
-
- 5.1 函數原型
- 5.2 安全問題
- (6)字元串搜尋函數
一、字元串
(1)字元串
1.1 字元數組
- List item
- char word[]={‘H’,‘e’,‘I’,‘I’,‘o’,’!’};
1.2 字元串
- char word[]={‘H’,‘e’,‘I’,‘I’,‘o’,’!’,’\0’};
- 以0(整數0)結尾的一串字元
- 0或’\0]是一樣的,但是和’0’不同
- 0标志字元串的結束,但它不是字元串的一部分
- 計算字元串長度的時候不包含這個0
- 字元以字元數組的形式存在,以數組或指針的形式通路
- 更多的以指針形式
- string.h裡有很多處理字元串的函數
1.3 字元串變量
- char *str=“Hello”;
- char word[]=“Hello”;
- char line[10]=“Hello”;
1.4 字元串常量
- “Hello”
- "Hello"會被編譯器變成一個字元串數組放在某處,這個數組的長度是6,結尾還有表示結束的0
- 兩個相鄰的字元串常量會被自動連接配接起來
1.5 總結
- c語言的字元串是以字元數組的形态存在的
- 不能用運算符對字元串做運算
- 通過數組的方式可以周遊字元串
- 唯一特殊的地方是字元串字面量可以用來初始化字元數組
- 以及标準庫提供了一系列字元串函數
(2)字元串變量
2.1字元串常量
- char *s = “Hello World”;
- s是一個指針,初始化為指向一個字元串常量
- 由于這個常量所在的地方,是以實際上s是const char* s,但是由于曆史的原因,編譯器接受不帶const的寫法
- 但是試圖對s所指的字元串做寫入會導緻嚴重的後果
- 如果需要修改字元串,應該用數組:
- char s[] = “Hello,world!”;
//可以編譯,但不能執行
#include<stdio.h>
int main(void)
{
char *s="Hello World";
s[0]='B';
printf("Here:s[0]=%c\n",s[0]);
return 0;
//字元串探究
#include<stdio.h>
int main(void)
{
int i;
char *s="Hello World";
char *s2="Hello World";
char s3="Hello World";
printf("i=%p\n",&i);
printf("s=%p\n",s);
printf("s2=%p\n",s2);
printf("s3=%p\n",s3);
s[3]=B;
printf("Here:s[0]=%c\n",s[0]);
printf("Here:s[3]=%c\n",s[3]);
return 0;
2.2 指針還是數組?- char* str=“Hello”;
- char word[]=“Hello”;
-
數組:這個字元串在這裡
作為本地變量空間自動被回收
- 指針:這個字元串不知道在哪裡
- 處理參數
- 動态配置設定空間
- 如果要構造一個字元串–>數組
- 如果要處理一個字元串–>指針
2.3 char*是字元串?
- 字元串可以表達為char*的形式
- char*不一定是字元串
- 本意是指向字元的指針,可能指向的是字元的數組(就像int*一樣)
- 隻有它所指的字元數組有結尾的0,才能說它指的是字元串
(3)字元串輸入輸出
3.1字元串指派?
- char *t=“title”;
- char *s;
- s=t
- 并沒有産生新的字元串,隻是讓指針s指向了t所指的字元串,對s的任何操作就是對t做的
- scanf讀入一個單詞(到空格、tab或回車為止)
3.2安全的輸入
- char string[8];
- scanf("%7s",string);
-
在%和s之間的數字表示最多允許讀入的字元的數量,這個數字應該比數組的大小小一
下一次scanf從哪裡開始?
3.3常見錯誤
- char *string
- scanf("%s",string);
- 以為char*是字元串類型,定義了一個字元串類型的變量string就可以直接使用了
- 由于沒有對string初始化為0,是以不一定每次運作都出錯
- 空字元串
- char buffer[100]="";
- 這是一個空的字元串,buffer[0]==’\0’;
- char buffer[]="";
- 這個數組的長度隻有1!
#include<stdio.h>
int main(void)
{
char word[8];
scanf("%7s",word); //防止數組越界
printf("%7s\n",word); //防止數組越界
return 0;
(4)字元串數組以及程式參數
4.1 字元串數組
- char **a
- a是一個指針,指向另一個指針,那個指針指向一個字元(串)
- char a[][10]
- a是一個數組,數組中的每一個單元相當于b[10]
- char *a[];
- a是一個指針,每個元素都指向字元串
4.2 程式參數
- int main(int argc,char const *argv[])
- argv[0]是指令本身
- 當使用Unix的符号連結時,反映符号連結的名字
#include<stdio.h>
int main(int argc,int const* argv[])
{
int i;
for(i=0;i<argc;i++){
printf("%d:%s\n",i,argv[i]);
}
return 0;
}
二、字元串函數
(1)單字元輸入輸出
1.1 putchar
- int putchar(int c);
- 向标準輸出寫一個字元
- 傳回寫了幾個字元,EOF(-1)表示寫失敗
1.2 getchar
- int getchar(void)
- 從标準輸入讀入一個字元
- 傳回類型是int是為了傳回EOF(-1)
- Windows–>Ctrl-Z
- Unix–>Ctrl-D
1.3 測試代碼
#include<stdio.h>
int main(int argc,char const *argv[])
{
int ch;
while((ch = getchar())!=EOF){
putchar(ch);
}
printf("EOF\n");
return 0;
}
(2)字元串函數strlen
2.1 函數原型
- size_t strlen(const char *s);
- 傳回s的字元串長度(不包括結尾的0)
2.2 測試代碼
//測試一下strlen
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char const *argv[])
{
char line[]="Hello";
printf("strlen=%lu\n",strlen(line));
printf("sizeof=%lu\n",sizeof(line));
return 0;
}
//自己寫一個strlen吧
size_t myStrlen(const char *str)
{
int count=0;
while(str[count]!='\0'){
count++;
}
return count
}
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char const *argv[])
{
char line[]="Hello";
printf("strlen=%lu\n",myStrlen(line));
printf("sizeof=%lu\n",sizeof(line));
return 0;
}
(3)字元串函數strcmp
3.1 函數原型
- int strcmp(const char *s1,const char *s2);
- 比較兩個字元串,傳回:
- 0:s1=s2
- 1:s1>s2
- -1:s1<s2
3.2 測試代碼
//測試一下strcmp()
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char const *argv[])
{
char s1[]="abc";
char s2[]="bbc";
printf("%d\n",strcmp(s1,s2));
return 0;
}
//自己寫一個MyStrcmp()
#include<stdio.h>
#include<stdlib.h>
int MyStrcmp(char const *str1,char const *str2)
{
while(*str1 == *str2 && *str1!='\0'){
str1++;
str2++;
}
return *str1-*str2;
}
int main(int argc,char const *argv[])
{
char s1[]="abc";
char s2[]="bbc";
printf("%d\n",MyStrcmp(s1,s2));
return 0;
}
(4)字元串函數strcpy
4.1 函數原型
- char* strcpy(char *restrict dst,const cahr *restrict src);
- 把src的字元串拷貝到dst
- restrict表明src和dst不重疊(C99)
- 傳回dst
- 為了能鍊起代碼來
4.2 測試代碼
//複制一個字元串
char *dst=(char*)malloc(strlen(src)+1); //注意要+1
strcpy(dst,src);
//測試一下strcpy
#include<stdio.h>
#include<string.h>
int main(int argc,char const *argv[])
{
char s1[]="abc";
char s2[]="abb";
strcpy(s1,s2);
return 0;
}
//自己寫一個MyStrcpy()
#include<stdio.h>
#include<string.h>
char* MyStrcpy(char *dst,const const char* src)
{
char *ret=dst;
while(*dst++=*src++)
;
*dst='\0';
return ret;
}
int main(int argc,char const *argv[])
{
char s1[]="abc";
char s2[]="abb";
MyStrcpy(s1,s2);
return 0;
}
(5)字元串函數strcat
5.1 函數原型
- char* strcat(char *restrict s1,const char *restrict s2)
- 把s2拷貝到s1後面,接成一個長的字元串
- 傳回s1
- s1必須具有足夠的空間
5.2 安全問題
- strcpy和strcat都可能出現安全問題
- 如果目的地沒有足夠的空間?
- 安全版本
- char* strncpy(char *restrict dst,const cahr *restrict src,size_t n);
- char* strncat(char *restrict s1,const char *restrict s2,size_t n)
- int strncmp(const char *s1,const char *s2,size_t n);
(6)字元串搜尋函數
- 字元串中尋找字元
- char* strchar(const char *s,int c);
- char *strrchr(const char *s,int c);
- 傳回NULL表示沒有找到
- 字元串中尋找字元串
- char *strstr(const char *s1,const char **s2);
- cahr *strcasestr(const char *s1,const char *s2);