C語言字符串
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h> // 包含字符串相關函數(shù)strlen()的原型的頭文件
#define PRAISE "You are an extraordinary being." // C預處理器 #define 定義常量為字符串 格式為 #define NAME value ,常量名和常量值用空格分隔,編譯器在編譯階段會將所有NAME替換為value,所以value可以是任意一段完整或不完整的代碼段
#define PI 3.14159
#include <float.h>
int main(void)
{
char name[20] = "Christine"; // c中使用char[]字符數(shù)組存儲字符串,每個ASCII字符占用數(shù)組的一個元素/byte,總共有9個字母,占用9個元素之外,字符串末尾必須用\0空字符串結束,所以存放9個字符的字符串需要10個元素的數(shù)組
char x = 'x'; // 定義字符x
printf("%s\n%zd\n%zd\n", name, strlen(name), sizeof name); // %s轉(zhuǎn)換說明用于輸出字符串形式 strlen()函數(shù)返回字符串的字符長度,不包含末尾的\0空字符,使用%zd轉(zhuǎn)換說明,而sizeof會返回變量占用的大小,因為賦予了name 20字節(jié)的數(shù)組,所以name占用的大小為20,無論是否實際使用
printf("What's you name?");
scanf("%s", name); // name前面不需要加&,根據(jù)%s轉(zhuǎn)換說明,scanf()在讀取到空白符\n\r\空格時結束,讀取輸入的"Angela Plains"只會將第一個單詞Angela賦值給name
printf("%s\n", name);
printf("%zd\t%zd\n", sizeof x, sizeof "x"); // 字符'x'占用1個字節(jié),char為基本類型,字符串"x"占用2個字節(jié)(數(shù)組存放字符x和空字符\0),char數(shù)組為派生類型
//sizeof運算符用于顯示 類型 占用大小時必須用括號如sizeof(int),用于顯示變量占用大小時可以用括號也可以只用空格隔開sizeof name/sizeof(name),推薦都使用括號的形式
printf("%s包含字符數(shù):%zd\n占用%zd字節(jié)\n", PRAISE, strlen(PRAISE), sizeof PRAISE); //包含31個字符,占用32字節(jié),因為末尾添加了\0空字符
//在編譯程序時,所有的常量PRAISE會被替換成定義的字符串,編譯時替換
printf("%20.2f\n", PI); // %20.2f中的20指最小字段寬度,通過這個轉(zhuǎn)換說明顯示的內(nèi)容至少占20個寬度,比如數(shù)字10占2個寬度,設定為20最小字段寬度后需要在數(shù)字10前面補18個空格占位,.2指精度,小數(shù)點后顯示兩位有效數(shù)字,所以結果為16個空格加數(shù)字3.14,如果要顯示的內(nèi)容所需寬度大于最小字段寬度則全部顯示出來
const int MONTHS = 12; // const關鍵字用于限定變量為只讀,constant常量,將MONTHS變量賦值12后設為只讀,在程序中不可修改,相當于一個常量
//printf("常見轉(zhuǎn)換說明:%a%A浮點數(shù)十六進制p記數(shù)法,%c單個字符,%d%i有符號十進制整數(shù),%e%E浮點數(shù)e記數(shù)法大小寫對應顯示結果中使用e還是E,%f浮點數(shù)十進制記數(shù)法,%g%G根據(jù)浮點數(shù)的值自動選擇%f或%e,%o無符號八進制整數(shù),%p指針,%s字符串,%u無符號十進制整數(shù),%x%X無符號十六進制整數(shù)大小寫對應結果中使用a-f還是A-F,%%轉(zhuǎn)義打印百分號");
//printf(格式字符串, 待打印項...) 格式字符串內(nèi)應包含每個待打印項對應的轉(zhuǎn)換說明
printf("%.2g\n", PI); // 對于%g轉(zhuǎn)換說明使用.2表示小數(shù)點前后總共顯示最多2位數(shù)字,結果為3.1
printf("%.2s\n", PRAISE); // 對于%s轉(zhuǎn)換說明使用.2表示最多顯示2個字符(從前往后)
printf("%.3d\n", 3); // 對于%d等整型轉(zhuǎn)換說明使用.3表示最少顯示3位,結果為"003",而使用%3d的結果為"? 3",兩個空格加3
//printf("%hu無符號short類型,%hx十六進制short類型,%6.4hd最小寬度為6最小位數(shù)為4位的short類型")
printf("%hhd\n", 65); // %hhd轉(zhuǎn)換說明表示char類型的值/1byte范圍的值,char類型也是整數(shù),這里顯示的值是1byte范圍內(nèi)的數(shù)字而非字符,%hhx十六進制char類型,%hhu無符號char類型
//printf("%jd表示intmax_t類型的值,intmax_t是<stdint.h>頭文件中規(guī)定的編譯器支持的最大整數(shù)類型,可能比long long int更大,%jd用來顯示intmax_t類型的值,%ju顯示uintmax_t類型的值")
//printf("%ld顯示long int,%lld顯示long long int,%Lf表示long double")
//printf("%zd表示size_t類型的值,size_t是sizeof返回的類型,strlen函數(shù)也返回size_t類型 ") <stdio.h>頭文件中包含的<stddef.h>頭文件將size_t定義成系統(tǒng)使用sizeof返回的類型,這被稱為底層類型underlying type
//printf("%td表示ptrdiff_t類型的值,pointer difference地址/指針差值,底層有符號整數(shù)類型")
//printf("%f顯示double類型的值,待打印項無論是表達式還是參數(shù),里面出現(xiàn)的float類型值會自動轉(zhuǎn)換成double類型,沒有float類型專用的轉(zhuǎn)換說明")
printf("%-5.3d\n", 2); // %-5.3d轉(zhuǎn)換說明中的符號-表示左對齊,%-5.3d表示左對齊的占至少5個寬度的至少3位的整數(shù),將待打印項2顯示為"002? "
printf("%+d\n", -2); // %+d的符號+表示顯示有符號值的符號,如果待打印項為2則顯示為"+2"
printf("% d\n% d\n", 2, -2); // % d百分號空格d的空格表示保留符號位,當待打印項為2時顯示為" 2"保留符號位,當待打印項為-2是顯示為"-2"正常顯示
printf("%#.0f\n", 3.0); // .0f和.f相同,不顯示小數(shù)點后數(shù)字,也不顯示小數(shù)點,%.f的結果為3,而%#.f使無論是否顯示小數(shù)都顯示小數(shù)點,結果為3.
printf("%#g\n", 3.0); // %g將3.0顯示為3,%#g將3.0顯示為3.00000,即默認精度的6位
//printf("%#o使八進制顯示為0開頭的形式,%#x使十六進制顯示為0x開頭的形式")
printf("%03d\n", 3); // %03d的0指使用數(shù)字0代替空格填充字段寬度,結果為003,如果出現(xiàn)%-負號或者%.2精度修飾會覆蓋0修飾的效果
const double RENT = 3852.99; // 設定常量
printf("\n*%f*\n", RENT); // 結果*3852.990000* 默認精度6位
printf("*%e*\n", RENT); // 結果*3.852990e+03* 默認精度6位
printf("*%4.2f*\n", RENT); // *3852.99* 最少占4寬度,顯示2位有效數(shù)字
printf("*%3.1f*\n", RENT); // *3853.0* 最少占3寬度,顯示1位有效數(shù)字,四舍五入進1
printf("*%10.3f*\n", RENT); // *? 3852.990*數(shù)字和小數(shù)點都占1寬度,加起來8寬度,前面用兩個空格占位
printf("*%10.3E*\n", RENT); // * 3.853E+03* e記數(shù)法3.85299精度3四舍五入變成3.853五個寬度,加上E+03四個寬度,前面有一個空格占位
printf("*%+4.2f*\n", RENT); // *+3852.99*顯示符號
printf("*%010.2f*\n", RENT); // *0003852.99*前面三個0占位
printf("%05.2d\n", 3); // 如果是.2d的話,.2的效果會覆蓋0的效果,結果為"? ?03",如果是.2f的話,0和.2不沖突
printf("The %4.4s family just may be $%06.2f dollars richer!\n", "Tomson", 3.1); // %4.4s使字符串最少占4寬度,并且最多顯示4個字符,結果為Toms,如果參數(shù)為"tom"則結果為" tom",%06.2f使浮點數(shù)最少占6寬度,并且顯示2位小數(shù)點后有效數(shù)字,不足6寬度前面補0,結果為003.10
short int num = -1;
printf("%hd\t%hu\n", num, num); // 結果為-1和65535,有符號的short用0-32767表示本身,用32768表示-32768(即32768-65536),用65535表示-1(即65535-65536),反過來說,有符號的-1則表示為無符號的65535(即65536-1)
// short類型-1會存儲為-1+65536即65535,當作為無符號顯示時表現(xiàn)為65535,當作為有符號顯示時表現(xiàn)為-1
printf("%hd\n", 65618); // int類型的65618顯示為short類型,4byte只讀取后2byte的值,相當于65618%65536(%模modulo),余數(shù)為82,結果為82,換種說法,short是2byte即16位二進制數(shù),最大值即全為1時是65535,再加1會進位到第17位,所以65618中的65536部分已經(jīng)超過了16位顯示在第17位的1,任何65536的整數(shù)倍的數(shù)都顯示在第17位以上的區(qū)域,所以只顯示后16位相當于去除掉17位以上的區(qū)域相當于減掉65536的倍數(shù)相當于模65536取余數(shù),結果為82
int size;
size = printf("%s\n", "a"); // printf()函數(shù)有返回值,正常情況下返回打印字符的個數(shù),如果有輸出錯誤會返回負數(shù)
printf("%d\n", size); // 結果為2,即printf()打印了字符'a'和'\n'兩個
int width = 10; // 寬度為10
int precision = 2; // 精度為2
printf("%*.*f", width, precision, 5.123); // printf()中在%和轉(zhuǎn)換字符之間使用*表示使用參數(shù)/變量來對該修飾賦值,格式化字符串后的參數(shù)列表中第一項對應%后第一個*即設定寬度為width的值,所以結果要至少占10個寬度,而第二個.*對應下一個參數(shù)precision的值.2,即精度為2,在兩個*的參數(shù)之后才是待打印項5.123,所以結果為六個空格加5.12
char s1[20], s2[20], s3[20]; // 聲明多個變量
scanf("%s%s%s", s1, s2, s3); // scanf的格式字符串之后的參數(shù)為指針,如果是基本變量類型需要前面加&,如果讀取多個參數(shù),scanf()會用空白符號\t\n\空格將輸入分段,輸入"a空格b回車c"時s1="a" s2="b" s3="c"空白符號不讀取,連續(xù)的空白符號會一同跳過,算一次分段
printf("%s\t%s\t%s", s1, s2, s3);
char ch;
scanf("%c", &ch); // 基本變量需要加&,輸入多個字符也只會讀取第一個字符賦值給ch,且不忽略空白符號,剩下的字符依舊保留在輸入隊列中
float f1;
scanf("%f", &f1); // scanf()函數(shù)的%f轉(zhuǎn)換說明僅用于float類型,如果需要讀取double類型則使用%lf
scanf("%lf把輸入解釋成double類型,%Lf把輸入解釋成long double類型")
scanf("%5s%s", s1, s2); //轉(zhuǎn)換說明中的修飾符數(shù)字5表示最大字段寬度,最多讀取5個寬度賦值給s1,如果中間遇到空白符號\n\t\空格即停止,下一個參數(shù)從第6個寬度或者空白符號開始
printf("%s\t%s", s1, s2);
scanf("%o把輸入解釋成無符號八進制,%x把輸入解釋成無符號十六進制")
int i1;
scanf("%d%s", &i1, s1); //scanf()使用%d轉(zhuǎn)換說明會逐個字符讀取,跳過開頭的空白符號,如果讀取到正負號或者數(shù)字會保存該字符繼續(xù)讀取,直到讀取到非數(shù)字的字符,會將該字符放回輸入,下一個%s從該字符開始讀取,如果是空白字符則跳過
printf("%d\t%s\n", i1, s1); // 如果輸入為"1abc"則scanf讀取到1賦值給i1,讀取到abc賦值給s1,即使中間沒有空白符號分隔也能正常運行
scanf("%d%s", &i1, s1); // 如果輸入的開頭為非數(shù)字或正負號如"a",則%d不賦值并將該字符放回輸入,該行scanf()函數(shù)停止執(zhí)行后續(xù)讀取,即i1/s1都沒有賦值
scanf("%s", s1); // 這個scanf()函數(shù)執(zhí)行時從剛才的輸入位置繼續(xù)讀取,直到之前的輸入讀取完為止不會讓用戶再次輸入,這時%s讀取到之前輸入的"a",賦值給s1
printf("%d\t%s\n", i1, s1); // 結果i1因為沒有賦值,顯示為無意義的數(shù),s1顯示為"a"
getchar(); //scanf使用%s讀到空白符即停止,也會將該空白符放回輸入,而通常用戶需要輸入回車來表示輸入結束,所以每次正常讀取完輸入都會將末尾的回車符/換行符放回輸入,而下一次getchar()會讀取放回的回車符/換行符,所以并不會產(chǎn)生阻塞,所以通常需要使用兩個getchar()來使程序停在結束之前
//舉一反三,如果上一次輸入的末尾除了回車還使用了其他空白符號,比如"a? \n"兩個空格加回車,scanf()讀取到第一個空格即停止,將這個空格放回輸入,這時需要連續(xù)使用到第四個getchar()才會等待用戶輸入阻塞
scanf("%d,%s", &i1, s1); // %d和%s之間有普通字符,逗號時,需要用戶按同樣的格式輸入“數(shù)字,字符串”,在%d完成匹配之后,格式字符串中的逗號會匹配輸入中數(shù)字之后的逗號,匹配時不跳過空白符號,所以輸入"1,a"和"1,? a"能正常識別但"1? ,a"不能正常識別
printf("%d\t%s", i1, s1); // s1中沒有存儲輸入中的逗號,如果輸入為"1,a"則i1為1,s1為"a"
scanf("%d ,%s", &i1, s1); //在逗號前面增加了空格,格式字符串中的空格表示匹配0個或多個空白符號,這時輸入"1? ?,? ?a"能夠正常執(zhí)行
i1 = scanf(" %c", &ch); //因為%c不會跳過空白,所以直接使用"%c"會匹配輸入的任何第一個字符,這時在%c前面加上空格,則會跳過所有空白將第一個非空白符號用%c匹配
printf("%c\t%d\n", ch, i1); // scanf()會返回成功讀取的項數(shù),所以i1為1,如果讀取出現(xiàn)錯誤會返回0,如果讀取到文件結束會返回EOF通常為-1
scanf("%*d%*d%d", &i1); // scanf()中在%和轉(zhuǎn)換字符之間用*表示當前轉(zhuǎn)換說明不參與賦值,如果輸入為"1 2 3"則前兩個%*d分別匹配到1和2,但不賦值,而第三個%d匹配到3,賦值給i1
printf("%d", i1); //結果為3
printf("%zd", strlen("His Hamlet was funny without being vulgar."));
return 0;
}