最近重新檢視資料結構,發現許多以前不懂,不清楚的問題。更加的意識到,以前學的C語言很基礎,許多細節書本上都沒講解,看來下次得找本C語言進階的書觀摩了。
1.在輸入字元串時,遇到輸入字元串有空格時會出現空格後面字元串接收不到的問題,如:
char str1[20],str2[20];
scanf("%s",str1);
scanf("%s",str2);
printf("%s,%s",str1,str2);
若想輸入"Holo is a wolf."給str1,"Super Sonic is beautiful."給str2,則隻會輸出"Holo,is",查閱MSDN知"Thescanf function reads data from the standard input streamstdin",scanf從stdin(以前學c是譚浩強的書,上面沒講)中讀取資料,應該是以空格或者回車來當作接收的斷點。想要接收包含空格的字元串,最好使用gets函數。代碼如下:
char str1[20],str2[20];
gets(str1);
gets(str2);
printf("%s,%s",str1,str2);
但是gets函數一般不建議使用,它容易造成緩沖區溢出,經搜查,一般建議使用fgets函數。常用fgets(char *str,int n,stdin);來擷取。如下:
char str1[5],str2[5]; /*記憶體較小,用啦測試會不會産生溢出*/
fgets(str1,(sizeof(str1)-1),stdin);/*sizeof(str1)-1,fgets函數會自動在末尾添加一個'\0',是以一般記憶體建議設足夠大。*/
fflush(stdin); /*如果沒有此句,如果輸入超過數組記憶體,會直接指派給下一個輸入函數。造成錯誤。*/
fgets(str2,(sizeof(str1)-1),stdin);/*當讀滿n-1個字元或者換行符時候,fgets函數會傳回。應該添加一個去回車的函數.此處暫不考慮*/
fflush(stdin);
printf("%s%s",str1,str2); /*輸出會有換行符*/
關于前面提到的fflush函數,由于有時候輸入資料長于緩存時,後面的輸入會直接從流讀入而不再接收使用者輸入經查找,需要用到此函數:
fflush(stdin)重新整理标準輸入緩沖區,把輸入緩沖區裡的東西丢棄 。
fflush(stdout)重新整理标準輸出緩沖區,把輸出緩沖區裡的東西列印到标準輸出裝置上。
一般在檔案操作中建議使用fflush(stdout),flush即清空緩沖,在慢速裝置上使用緩存是一種提升資料處理效率的手段,flush的作用是将記憶體中緩沖的内容實際寫入外存媒介。fflush不應該在讀取檔案的時候用,而應該在寫入檔案的時候用。fflush會清空緩沖區,fclose在關閉檔案之前也會清空緩沖區。如果使用exit函數退出程式,或者main函數傳回,則所有打開後沒有關閉的檔案會自動關閉,關閉時也會清空緩沖區。
2.strcmp(a,b)要include <string.h>頭檔案,當兩兩字元串相等時傳回0,a>b即從做往右a有大于b的AssicⅡ時,傳回1,反之傳回0.要小心使用
if(!strcmp(a,b))func();,對于一個數字a,它的非值為0.這個表示如果a,b相等,則執行func(),不等則不執行.對于在字元串數組中找某字元串有如下代碼:
int i=0;
while(0!=strcmp(v,G.vexs[i]))i++;/*G.vexs表示圖的頂點,在vexs裡面找v,*/
if(i<G.vexnum) /*while隻是用來确定所在位置。像這種确定字元串位置的*/
return i; /*一般用這種方法較好,先用循環确定位置i*/
else{printf("Cannot find data %s!\n",v);exit(0);}
3.i++和++i,在需要他們傳回數值的時候才有差別,i++是先傳回i的值,再将i加1,++i則是先将i加1,再傳回i的值,此用法在循環中我了解出錯了,如循環
for(int i=0;i<5;++i);我認為第一次執行時是先将i+1,即等價于for(int i=1;i=<5;i++);其實不然,經彙編分析,括号内的是從左到右執行。其實在循環中,沒有
用到i++或++i的傳回值,此處他們等價。關于他們效率的問題,在編譯器優化前,++i不需要零時變量效率高,但經編譯器優化Release版本,實質是一樣的。
參考網文,在有疊代器的時候,++i效率高些。關于疊代器暫時還未看,不過書中一般循環中用++i。反彙編代碼自尋。
4.關于switch語句中遇見enum類型。在switch中有個規定,隻能針對基本資料類型使用switch,這些類型包括int、char等。而在union輸入enum時接收的是
字元串類型,需要将其化為enum類型。有時也需要将enum類型傳回字元串類型。其代碼如下
void strToenum(MGraph &G)/*将字元串轉換成enum type kind定義typedef enum{DG,DN}Kind; Kind kind;*/
{
char str[10];
scanf("%s",str);
if(!strcmp(str,"DG"))G.kind=DG;
else if(!strcmp(str,"DN"))G.kind=DN;
else {printf("Error Typed!\n");exit(0);}
}
将枚舉轉換成字元串
typedef enum{Mon,Tus,Wen,Thr,Fri,Sta,Sun}Week;
char temp[7][4]={"Mon","Tus","Wen","Thr","Fri","Sta","Sun"};
printf("\n%s",temp[Mon]);/*用數組法就直接得出結果來了*/
5.關于編譯器給存儲在棧上變量配置設定存儲空間時,誰在前面聲明,就先給誰開辟空間。如:
char p[4],q[4];
36: scanf("%s",p);
0040D418 lea eax,[ebp-4]
0040D41B push eax
0040D41C push offset string "%s" (004223f4)
0040D421 call scanf (0040f8f0)
0040D426 add esp,8
39: scanf("%s",q);
0040D43A lea edx,[ebp-8]
0040D43D push edx
0040D43E push offset string "%s" (004223f4)
0040D443 call scanf (0040f8f0)
0040D448 add esp,8
char p[4],q[4];
scanf("%s",p);
scanf("%s",q);
printf("%d,%d",p[0],q[0]);
(圖中數字為10進制)堆棧在系統上如下圖1:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIXZ05WZD9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvw1do5WYtVzRaZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zNzkjM1IjMzITOwkDMzEDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
圖1
圖2
圖3
圖4
對于下面代碼,如果輸入"aaaa","bbbb",則會輸出0,98本來是想輸出p和q的第一個的AssicⅡ碼,結果卻不盡人意,原本要成為圖2的,但是分析是scanf函數獲得字元串會在後面預設加個‘\0’來表示字元串的末尾,本來q隻申請了四個空間,此時會将'\0'填充到下面p的首部,便成了如上圖3。在一個變量内,其值一般是按照從小位存低位,大位存高位(RISC架構)如上圖4,1234存儲方式。
char p[4],q[4];
a=3;
b=4;
scanf("%s",p);
scanf("%s",q);
printf("%d,%d",p[0],q[0]);
小注意:會發現如果上面的p[4]變成p[2]或者p[1]時,p的位址依然是ebp-4,q的位址是ebp-8說明對于數組大小小于4位元組時預設配置設定4位元組,當大與4位元組時按具體大小配置設定。(可能一個指針占4位元組是以預設配置設定4位元組)。同時注意到如果隻是定義一個char a;它也會配置設定4個位元組的空間,難道是為了位元組對齊?本機機器字長為32位4位元組,一次能處理32位,則一位元組申請32位空間嗎?大概。ebp為本段程式的基址,一般隻對它進行減法操作,來取得變量位址,是為了保護不是本段程式的變量嗎,也大概。得參考深入的C語言書籍了。
其他一些後續問題還會添加,現在才覺得以前學的C語言根本不夠用啊,好像學C語言不僅要從底層彙編了解,還要從編譯器方向來考慮,有些還涉及到CPU的處理,如以前遇到的浮點數要初始化浮點數寄存器問題,是該找本好書系統學習了,求推薦orz