五大板块(5)——字符串
參考:五大板塊(5)——字符串
作者:丶PURSUING
發(fā)布時間: 2021-03-18 16:03:48
網(wǎng)址:https://blog.csdn.net/weixin_44742824/article/details/114982019
目錄
- 一、字符串的定義方式與輸出
- 二、字符串的結尾是 ’ \0 ’
- 所以用strlen計算有效字符的長度
- strlen使用(1)注意字符數(shù)組當做字符串來用?
- 三、字符串操作常用API
- puts、gets —— 輸入與輸出
- 不安全的gets
- 對比get和fgets
- strcpy、strncpy —— 拷貝
- strcmp —— 比較
- strchr、strstr —— 檢索
- strlwr、strupr —— 大小寫轉換
- strcat —— 拼接
- strtok —— 分割(作為重點介紹)
- strtok容易出錯的秘密
- sprintf —— 最常用的帶格式字符串拼接函數(shù)
- 四、自己實現(xiàn)這些API
- 1.puts
- 2.gets
- 3.mystrlen
- 4.mymemset
- 5.mystrcpy
- 6.strcmp
- 7.mystrcat
- 8.字母大小寫的轉換
- 9.輸入年月日時分秒,輸出該年月日時分秒的下一秒
- 10.平年閏年判斷
- 11.輸入一個日期,計算這一天是周幾
- 12.數(shù)組實現(xiàn)輸入某年某月某日,判斷這一天是這一年的第幾天
- 13.itoa和atoi函數(shù)的使用和自己實現(xiàn)
一、字符串的定義方式與輸出
#include <stdio.h> #include <stdlib.h> #include <string.h>int main() {int i;//定義方式一char str1[3] = {'a','b','c'};//定義方式二char str2[3] = "abc";//定義方式三char str3[] = "chen li chen mei wo shuai";//輸出方式一:for循環(huán)拼接多個字符for(i=0;i<sizeof(str3)/sizeof(str3[0]);i++){printf("%c",str3[i]);}//輸出方式二:printf("%s\n",str3);//輸出方式三:調用字符串APIputs(str3);return 0; }結果:
chen li chen mei wo shuaichen li chen mei wo shuai chen li chen mei wo shuai- 1
- 2
其中第三種定義方式 char str3[] = "str"; 不指明數(shù)組的大小,只給出了數(shù)組名,而數(shù)組名的值是個指針常量,也就是數(shù)組第一個元素的地址。
是不是可以猜想,首地址就是字符串的關鍵呢?
而指針也指明了地址,故可以用指針的方式定義字符串,即字符串指針。也是定義字符串的常用方式。
char* name = "huatianzhu";- 1
注意: 這里說的定義是同時賦值,而不是等待賦值。之所以不需要給指針name分配空間,是因為進行了初始化,編譯的時候系統(tǒng)就知道需要分配多大的空間,否則要開辟空間。(后文中也有涉及)。
二、字符串的結尾是 ’ \0 ’
字符串都是以類似于下面的方式輸出:遇到 ‘\0’
#include <stdio.h>int main() {int i;char str[] = "abcd";while(str[i] != '\0'){printf("%c",str[i]);i++;}return 0; }所以用strlen計算有效字符的長度
在很多場景,我們都需要在程序的執(zhí)行過程中錄入字符串,如下:
#include <stdio.h> #include <string.h>int main() {char name[128];//系統(tǒng)預分配空間printf("請輸入名字\n");scanf("%s",name);//才能進行賦值printf("sizeof計算:%d\n",sizeof(name)/sizeof(name[0]));printf("strlen計算:%d\n",strlen(name));return 0; }運行結果:
請輸入名字 huatianzhu sizeof計算:128 strlen計算:10- 1
- 2
- 3
- 4
實際上huatianzhu長這樣:
huatianzhu\0\0\0\0.....- 1
strlen當遇到\0時便停止計算,是專門用來計算字符串的長度。
這時候你好奇了,輸入中文字符,用strlen計算是多少?
輸入:
華天朱- 1
可以發(fā)現(xiàn)結果是 9.這與linux系統(tǒng)采用utf-8的編碼方式相關,一個漢字占用3個字節(jié)。
strlen使用(1)注意字符數(shù)組當做字符串來用?
有一個說法是:把字符數(shù)組當做字符串來使用時,最后一個元素要是'\0',否則strlen()計算時就會發(fā)生“停不下來”,直到遇到內存的'\0',故計算出來就不會是一個準確的值。例如:
#include <stdio.h> #include <string.h>int main() {char array[5] = {'a','b','c','d','e'};printf("%d\n",strlen(array));return 0 ; } 可我放在樹莓派上運行,結果都是5。而在啊哈C中,都是6。- 1
三、字符串操作常用API
字符串操作函數(shù)的使用方法都很簡單,在這里做個系統(tǒng)的了解,之后想用不會直接面向百度開發(fā)即可。
puts、gets —— 輸入與輸出
#include <stdio.h> #include <string.h> #include <stdlib.h>int main() {char* str = (char *)malloc(128);//直接賦值NULL不行,必須malloc開辟空間 有筆有紙才能寫if(str == NULL){printf("malloc error\0");//malloc開辟空間可能會失敗 同時注意內存泄漏exit(-1);}memset(str,'\0',128);printf("請輸入任意字符串\n");gets(str);puts(str);//內置了一個\nreturn 0; }結果:
請輸入任意字符串 chenlichen chenlichen- 1
- 2
- 3
不安全的gets
哎嘿!有個小警告挺有意思:
warning: the `gets' function is dangerous and should not be used.- 1
用這個就可以:
fgets(str,128,stdin);//128為size- 1
為什么?
對比get和fgets
fgets從stdin中讀字符,直至讀到換行符或文件結束,但一次最多讀size個字符。讀出的字符連同換行符存入緩沖區(qū)str中。返回指向str的指針。
而gets把從stdin中輸入的一行信息存入cmd中,然后將換行符置換成串結尾符NULL。用戶要保證緩沖區(qū)的長度大于或等于最大的行長。
注意gets的行為與fgets使用stdin作為參數(shù)時的行為不完全一樣:首先,gets不包含結束的換行符,而fgets包含。其次,gets不允許指定要讀取的字符數(shù)量的限制,因此必須小心str所指向的數(shù)組的大小,以避免緩沖區(qū)溢出。
所以呢?用fgets咯。
strcpy、strncpy —— 拷貝
char *strcpy(char* dest, const char *src);
把從src地址開始且含有NULL結束符的字符串復制到以dest開始的地址空間
char *strncpy(char *destinin, char *source, int maxlen);
把src所指向的字符串中以src地址開始的前maxlen個字節(jié)復制到dest所指的數(shù)組中,并返回被復制后的dest
#include <string.h> #include <stdlib.h>int main() {char* strDes = (char*)malloc(128);//不開辟空間就是野指針 會出現(xiàn)斷錯誤memset(strDes,'\0',128);char* strSrc = "clc mws";puts(strcpy(strDes,strSrc));memset(strDes,'\0',128);strncpy(strDes,strSrc,3);puts(strDes);return 0; }結果:
clc mws clc- 1
- 2
strcmp —— 比較
extern int strcmp(const char *s1,const char *s2);
當s1<s2時,返回為負數(shù); 當s1=s2時,返回值= 0; 當s1>s2時,返回正數(shù)。- 1
- 2
- 3
僅做簡單的示范:
#include <stdio.h> #include <string.h>int main() { char str1[128]={'\0'};char str2[128]={'\0'};//最快的開辟字符串空間并初始化puts("請輸入字符串1"); fgets(str1,128,stdin); //stdin標準輸入puts("請輸入字符串2");fgets(str2,128,stdin);if(strcmp(str1,str2) == 0){printf("一樣\n");}else{printf("不一樣\n");}return 0; }strchr、strstr —— 檢索
char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出現(xiàn)字符串 needle 的位置,不包含終止符 ‘\0’,并且返回第一次出現(xiàn)字符串 needle (strchr檢索的是字符)的位置,注意了,是返回第一次出現(xiàn)的位置,不是返回字符串needle,很多人有這個誤解
#include <stdio.h> #include <string.h> #include <stdlib.h>int main() {char haystack[32] = "chenlichen mei wo shuai";char needle[32] = {'\0'};char* ret = NULL;//ret = (char* )malloc(32);//如果不在while中malloc,將會段錯誤//ret的值是變化的,要一直動態(tài)分配空間while(1){ret =(char* )malloc(32);memset(ret,'\0',32);memset(needle,'\0',32);//而這個字符數(shù)組只需要擦除原有數(shù)據(jù)printf("現(xiàn)有字符串:%s,請輸入需要檢索的字段\n",haystack);//fgets(needle,32,stdin);//不明白為啥用這個一個no find//printf("%s\n",needle);//明明這里也可以輸出正常scanf("%s",needle);ret = strstr(haystack,needle);//這里的賦值決定了ret只能被定義為字符指針,而不是數(shù)組。if(ret != NULL){printf("子字符串是:%s\n",ret);}else{puts("no find");}}return(0); }運行結果:
現(xiàn)有字符串:chenlichen mei wo shuai,請輸入需要檢索的字段 chen 子字符串是:chenlichen mei wo shuai現(xiàn)有字符串:chenlichen mei wo shuai,請輸入需要檢索的字段 wo 子字符串是:wo shuai現(xiàn)有字符串:chenlichen mei wo shuai,請輸入需要檢索的字段 shuai 子字符串是:shuai未解決的問題,為什么用fgets(needle,32,stdin);而不用scanf的時候,無論輸入什么都是no find,用prinrf檢測了,明明也正確fgets到字符串了。
現(xiàn)有字符串:chenlichen mei wo shuai,請輸入需要檢索的字段 mei no find現(xiàn)有字符串:chenlichen mei wo shuai,請輸入需要檢索的字段 chen no find現(xiàn)有字符串:chenlichen mei wo shuai,請輸入需要檢索的字段 shuai no findstrlwr、strupr —— 大小寫轉換
strlwr和strupr不是標準C庫函數(shù),只能在VC中使用。linux gcc環(huán)境下需要自行定義這個函數(shù)。
如下:
#include <stdio.h>char* strlwr(char *str) {if(str == NULL)return NULL;char *p = str;while (*p != '\0'){if(*p >= 'A' && *p <= 'Z')*p = (*p) + 0x20;//大小寫差32p++;}return str; }char* strupr(char *str) {if(str == NULL)return NULL;char *p = str;while (*p != '\0'){if(*p >= 'a' && *p <= 'z')*p = (*p) - 0x20;p++;}return str; }int main() {char str[128] = {'\0'};printf("請輸入字符串\n");fgets(str,128,stdin);printf("轉換為小寫:%s\n",strlwr(str));printf("轉換為大寫:%s\n",strupr(str));return 0; }結果:
請輸入字符串 niYeXiHuanJKma老哥 轉換為小寫:niyexihuanjkma老哥轉換為大寫:NIYEXIHUANJKMA老哥strcat —— 拼接
extern char *strcat(char *dest, const char *src);
把src所指向的字符串(包括“\0”)復制到dest所指向的字符串后面(刪除*dest原來末尾的“\0”),*src中原有的字符不變。返回指向dest的指針。
要保證dest足夠長,以容納被復制進來的src。
簡單的示范:
#include <stdio.h> #include <string.h>int main() {char str1[32] = "chenlichen";char str2[] = "meiwoshuai";//拼接后放在str1,所以str1的長度在定義的時候必須指明并且足夠大puts(strcat(str1,str2));return 0; }結果:
chenlichenmeiwoshuai- 1
strtok —— 分割(作為重點介紹)
demo1:
#include <stdio.h> #include <string.h>int main(void) {char s[] = "aaa bbb ccc ddd";char c[] = " ";char *r = strtok(s, c);while (r != NULL) {printf("%s\n", r);r = strtok(NULL, c);//獲取下一個串的方式比較奇葩,目標字符串改為NULL}return 0; }輸出結果:
aaa bbb ccc ddddemo2:
#include <string.h>#include <stdio.h>#include <stdlib.h>void main() {//字符串分割:strtok—頭文件: #include <string. h>//函數(shù)原型: char *strtok(char* str,const char* delimiters);//參數(shù): str: 待分割的字符串(c-string) ; delimiters: 分割符字符串。char* p = (char*)malloc(128);memset(p,'\0',128);//char* p = NULL; 這樣也可以 防止野指針//char* str2 = "ni,hao,zhe,ge,shi,jie"; 這種方法不可以!!char str2[] = "ni,hao,zhe,ge,shi,jie";p = strtok(str2,",");if (p == NULL) {printf("無法分割");}else puts(p);//else printf("%s",p); 兩中輸出方式都可以 此種輸出效率更高puts(strtok(NULL,","));//獲取下一個串的方式比較奇葩,目標字符串改為NULLputs(strtok(NULL,","));//獲取下一個串的方式比較奇葩,目標字符串改為NULLputs(strtok(NULL,","));//獲取下一個串的方式比較奇葩,目標字符串改為NULLputs(strtok(NULL,","));//獲取下一個串的方式比較奇葩,目標字符串改為NULLsystem("pause");}輸出結果:
ni hao zhe ge shistrtok容易出錯的秘密
sprintf —— 最常用的帶格式字符串拼接函數(shù)
#include <stdio.h> #include <string.h>int main(){char s[64];char* who = "I";char* whom = "CSDN";sprintf(s, "%s love %s.", who, whom); //產(chǎn)生:"I love CSDN. " 這字符串寫到s中puts(s);sprintf(s, "%10.3f", 3.1415626); //產(chǎn)生:" 3.142"puts(s); }四、自己實現(xiàn)這些API
#include<stdio.h> #include<string.h>void myputs(char*p) {while (*p!='\0'){putchar(*p++);}putchar('\n'); }int main() {char* p = "hello world";puts(p);myputs(p);system("pause");} #include<stdio.h> #include<string.h>void mycopy(char*dest,const char*src) {if (dest == NULL || src == NULL) {return NULL;}while (*src != '\0'){*dest = *src;dest++;src++;}return dest; }int main() {//char* dest = (char* )malloc(128);//memset(dest,'\0',128);char dest[]={'\0'}; //上面的也可以char* src = "qwer";mycopy(dest,src);puts(dest);system("pause");}下面這部分引用:
網(wǎng)址:https://blog.csdn.net/weixin_43732386/article/details/115659118
作者:糯米啊啊
1.puts
#include <stdio.h>void myputs(char *p) {while(*p != '\0'){putchar(*p++);}printf("\n"); }int main() {char *str = "nuominuomi,qiangdeyipi";myputs(str);return 0; }2.gets
#include <stdio.h> #include <stdlib.h>void mygets(char *p) {if(p == NULL){exit(-1);}while(*p = getchar()){if(*p == '\n'){return;//用break也可以}else{p++;}} } int main() {char str[128] = {'\0'};printf("請輸入字符串:\n");mygets(str);puts(str);return 0; }3.mystrlen
#include <stdio.h> #include <stdlib.h> int mystrlen(char *p) {int cnt = 0;while(*p != '\0'){cnt++;p++;}return cnt; } int main() {char *str = "qdasdqwdaddwqd";printf("str的長度為:%d\n",mystrlen(str));return 0; }4.mymemset
#include <stdio.h> #include <stdlib.h> int mymemset(char *p,char c,int size) {while(size){*p++ = c;size--;} }int main() {char *str = NULL;str = (char *)malloc(128);mymemset(str,'a',128);puts(str);return 0; }5.mystrcpy
#include <stdio.h> #include <stdlib.h> char * mystrcpy(char dest[],char *src) {if(dest == NULL || src == NULL){return NULL;}while(*src != '\0'){*dest++ = *src++;}*dest = '\0';return dest;//返回的是數(shù)組的首地址 指針的話要注意回調 }int main() {char dest[128] ={'\0'};char *src ="this is a mystrcpy test";mystrcpy(dest,src);puts(dest);return 0; }6.strcmp
#include <assert.h> #include <stdio.h> #include <stdlib.h> int mystrcmp(char *str1,char *str2) {assert(str1);//assert宏的原型定義在<assert.h>中assert(str2);//其作用是如果它的條件返回錯誤,則終止程序執(zhí)行 https://www.cnblogs.com/cpoint/p/3367326.htmlwhile(*str1 == *str2){if(*str1 == '\0') {return 0;}str1++;str2++;}return *str1-*str2;}int main() {char *str1="hello";char *str2="hello";int ret = mystrcmp(str1,str2);if(ret == 0){printf("倆字符串相等\n");}else if(ret > 0){printf("字符串一比字符串二大\n");}else{printf("字符串一比字符串二小\n");}return 0; }7.mystrcat
#include <stdio.h> #include <stdlib.h> char * mystrcat(char dest[],char *src) {while(*dest!='\0'){//遍歷到尾巴dest++;}while(*src != '\0'){*dest++ = *src++;}*dest = '\0';return dest; }int main() {char dest[128] ="hello ";char *src ="this is a mystrcat test";mystrcat(dest,src);puts(dest);return 0; }8.字母大小寫的轉換
#include<stdio.h>void main() {char a; printf("請輸入一個字母:");scanf("%c",&a);if(a <= 91) //對應ASCII表判斷輸入字母的ASCII值,大寫字母A~Z的ASCII值為65~91{a = a +32; //字母a~z的ASCII值為97~123,則給該字符加32之后,他的ASCII值變?yōu)閷男懽帜傅腁SCII值printf("該子母的小寫形式為:%c\n",a);}else{a = a-32; //同大寫變小寫的ASCII值的轉換printf("該子母的大寫形式為:%c\n",a);}}9.輸入年月日時分秒,輸出該年月日時分秒的下一秒
編寫一個函數(shù),要求輸入年月日時分秒,輸出該年月日時分秒的下一秒。如輸入2004年12月31日23時59分59秒,則輸出2005年1月1日0時0分0秒
考慮如何幾種情形
算法思路:
(1) 判斷現(xiàn)在月份是大月還是小月
大月:1月,3月,5月,7月,8月,10月,12月(31天)
小月:2月(28天或者29天),4月,6月,9月,11月(30天)
(2) 2月份要判斷是平年還是閏年,平年28天,閏年29天
(3) 考慮幾種邊界情況:
(3.1) year<0||month<1||month>12||date<1||date>31||hour<0||hour>23||minute<0||minute>59||second<0||second>60
考慮定義一個數(shù)組
Month_days[12]={31,28,31,30,31,30,31,31,30,31,30,31}
閏年時Month_days[1]=29,閏年判斷條件如下:
year%400 == 0||year%100 != 0&&year%4 ==0
(3.2)
考慮下一秒的設置:
完整代碼:
#include<iostream> #include<stdlib.h> using namespace std;int NextTime(int year,int month,int date,int hour,int minute,int second) {int Days=0;//首先判斷輸入日期格式是否正確if(year<0||month<1||month>12||date<1||date>31||hour<0||hour>23||minute<0||minute>59||second<0||second>59){cout<<"格式輸入錯誤!!!"<<endl;}second+=1;if(second==60){second=0;minute+=1;if(minute==60){minute=0;hour+=1;if(hour==24){hour=0;date+=1;switch(month){case 1:case 3:case 5:case 7:case 8:case 10:case 12:Days=31;break;case 2:if(year%400==0||year%100!=0&&year%4==0){Days=29;}else{Days=28;}break;default:Days=30;break;}if(date>Days){date=1;month+=1;}if(month>12){month=1;year+=1;}}}}cout<<"下一秒是"<<year<<"年"<<month<<"月"<<date<<"日"<<hour<<"時"<<minute<<"分"<<second<<"秒"<<endl;return 1; }int main() {int YEAR,MONTH,DATE,HOUR,MINUTE,SECOND;cout<<"請輸入年份&月份&天數(shù)&小時&分鐘&秒數(shù)"<<endl;cin>>YEAR>>MONTH>>DATE>>HOUR>>MINUTE>>SECOND;cout<<"您輸入的是"<<YEAR<<"年"<<MONTH<<"月"<<DATE<<"日"<<HOUR<<"時"<<MINUTE<<"分"<<SECOND<<"秒"<<endl;NextTime(YEAR,MONTH,DATE,HOUR,MINUTE,SECOND);system("pause");return 0; }測試用例:
10.平年閏年判斷
#include <stdio.h> #include <stdlib.h>int main() {int a,y;printf("input the year:");scanf("%d",&y);if (y%4 == 0){ if (y%100 == 0){if (y%400 == 0)a = 1;elsea = 0;}elsea = 1;} elsea = 0;if (a == 1)printf("%d is leap year!\n",y);elseprintf("%d is common year!\n",y);system("pause");return 0; }11.輸入一個日期,計算這一天是周幾
#include <stdio.h> #include <stdlib.h>int main() {int unknowYear,unknowMouth,unknowday;int knowYear=2020, knowMouth=11, knowday=2;//周一int year=0, mouth=0, day=0;int Day=0;int week;printf("請輸入年 月 日:");scanf("%d %d %d", &unknowYear, &unknowMouth, &unknowday);//輸入一個數(shù) 加一個空格 完全按照輸入格式輸入Day = (unknowYear - knowYear) * 360 + (unknowday - knowday) + (unknowMouth - knowMouth) * 30;if (Day >= 0){week = 1 + Day % 7;}else{week = 7 + Day % 7;}printf("%d\n", week);system("pause");return 0; }12.數(shù)組實現(xiàn)輸入某年某月某日,判斷這一天是這一年的第幾天
#include <stdio.h> int main() {int day,month,year,sum,leap;int a[13]= {0,31,59,90,120,151,181,212,243,273,304,334};printf("please input year month day(year month day)\n");scanf("%d %d %d",&year,&month,&day); // 格式為:2015 12 10 2015 10 1sum=a[month-1]+day; // 再加上某天的天數(shù)if(year%400==0||(year%4==0&&year%100!=0)) // 判斷是不是閏年leap=1; // 是則記錄為1elseleap=0; // 不是記錄為0if(leap==1&&month>2) // *如果是閏年且月份大于2,總天數(shù)應該加一天{sum++;}printf(" %d ",sum);printf("\n");return 0; }13.itoa和atoi函數(shù)的使用和自己實現(xiàn)
整型數(shù)轉字符,或者字符轉整型數(shù)是編程中比較常見的類型轉換。
itoa()函數(shù)和atoi()函數(shù)并非標準C庫函數(shù),大多數(shù)編譯器的stdlib.h庫中包含,如果沒有的話需要自己實現(xiàn)。
1. itoa()
函數(shù)原型:char *itoa(int value, char *string, int radix);
- value:要轉換的整型數(shù)
- string:存儲字符串的數(shù)組地址
- radix:進制。2~36進制
功能及返回值:
- 將一整型數(shù)轉換為字符串
- 返回指向string的指針
應用舉例:
函數(shù)自己實現(xiàn):
- 如果庫函數(shù)中不自帶該函數(shù),需要自己實現(xiàn)
結果:
-100000000000 -2210212 -200000 -31143 -13252 -5654 -4000 -2725 -2048 -15a2 -1228 -c17 -a64 -918 -800 -718 -65e -5cf -528 -4db -452 -3k1 -3d8 -36n -30k -2ln -2h4 -2ci -288 -242 -200 -1t2 -1q8 -1ni -1kw2. atoi()
函數(shù)原型:int atoi(const char *str);
功能:將字符串轉換為整型數(shù)輸出
頭文件:stdlib.h
返回值:
- 成功:返回整型數(shù)
- 失敗:比如無法轉換為int類型的值,返回0(所以無法區(qū)分轉換失敗還是轉換本身就是0)
應用舉例:
函數(shù)自己實現(xiàn):
- 如果庫函數(shù)中不自帶該函數(shù),需要自己實現(xiàn)
結果:
-123總結
以上是生活随笔為你收集整理的五大板块(5)——字符串的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu 1016
- 下一篇: 国内外大数据经典案例研究