果然開學一個禮拜後就有
常數指標 ? 指標常數 ?
我們先來看看下列的程式碼宣告:
- const int a = 1;
- a = 2; // error
很明顯的 B 行會發生錯誤,因為整數 a 的值不能改變 (常數)。
那如果 a 的型態是指標呢? 那就有點意思了 我們來看看以下三種宣告:
- const int* const a; // const pointer to constant
- const int* a; // pointer to constant
- int const* a; // pointer to constant
- int* const a; // constant to integer
是不是看的頭暈了? 回憶的一位朋友提供了一個簡單的辦法:
看 const 位於什麼型態的後面,唯一的例外是 B 行
我們以比較特殊的 B 行做舉例:
由於 const 沒有在類型的後面,自動將他往後丟一個(等價於 C 行)
可以看到 const 位於 int 後面,因此該指標指向的是常數 (不可變)
不是指標不可變
說實話這個問題用中文記憶很容易搞混,建議使用英文理解 (如同 code 區的註解)
strtok
strtok 函數在字串處理相關的程式很常見
但相信很多人和回憶一樣覺得這函數的用法很難記
每次要打的時候都要上網再查詢一次用法
這次回憶想到一個比較好記憶的方式,就從理解他的參數下手
我們先來看看函數宣告
char * strtok ( char * str, const char * delimiters );
//from http://www.cplusplus.com/reference/cstring/strtok/
以下列出幾個要點
- 此函數尋找目標為 delimiters 中任意一字元
- 忽略起始符合字元(不顯示),直至發現不符合字元後,將第一個發現的符合字元改成 '\0' ,請看下方分析
- 第一個參數 str 可以指向一個字串或是空指標,若為空指標,則延續上一次找到的地方往下尋找
- delimiters 參數可改變
在這裡我們用以下程式碼來做測試
- #include <stdio.h>
- #include <string.h>
- int main(void){
- int i,j = 0;
- //char* test = "testascaddava"; // error
- char test[] = "testascaddava"; // no special meaning, only for demonstration
- char* pch;
- char* delimiters ="abcdefg"; // used for altering delimiters
- pch = strtok (test, "t");
- while(pch != NULL){
- printf ("%s\n",pch);
- pch = strtok (NULL, delimiters+j);
- j ++;
- }
- printf("\n");
- for(i = 0; i < 13; i++)
- printf("%c",test[i]); // print the whole string
- printf("\n");
- for(i = 0; i < 13; i++)
- printf("%d ",test[i]); // print the whole string in number format
- return 0;
- }
執行結果:
s
a
ava
tes as a dava
116 101 115 0 97 115 0 97 0 100 97 118 97
Process returned 0 (0x0) execution time : 0.016 s
Press any key to continue.
我們來做個簡單的分析:
字串狀態 (test) | 比對字串 (delimiters) | 附註 | |
第一次 | testascaddava | t | test[3]='\0' |
第二次 | tes ascaddava | abcdefg | test[6]='\0' |
第三次 | tes as addava | bcdefg | test[8]='\0' |
第四次 | tes as a dava | cdefg | 讀到'\0' |
我們可以看到第一次操作過程中,第一個符合字元 't' 並未被修改成'\0' ,只是不顯示在輸出中
請問G行會報錯的原因是因為它等同於下列哪一個宣告?
- const char
- const char*
- char* const
- char const* ANS: B or D
到底甚麼時候 eof ?
一般遇到讀檔問題時可能會使用 int feof(FILE*) 來判斷結束
可是此函數在 C / C++ 使用時,必須是讀到 EOF 才會等於 1
我們來看看下列的程式碼
- #include <stdio.h>
- #include <string.h>
- int main(void){
- char mem[1000] = {'\0'};
- FILE* file = fopen("test.txt", "r");
- if(!file){
- puts("cannot open file!");
- return 0;
- }
- while(!feof(file)){
- memset(mem, 0, sizeof(mem));
- fgets(mem, sizeof(mem), file);
- printf("%s", mem);
- }
- return 0;
- }
執行結果:
This is a test string.
Process returned 0 (0x0) execution time : 0.085 s
Press any key to continue.
看起來似乎沒有什麼問題?
有些人會提出 feof 不應該放在 while 迴圈裡
但是目前在回憶的測試中是正常的
所以問題出在哪?
我們來看看以下4個檔案:
黑底的是在 linux (freeBSD 10.3 - release) 底下使用 vim 編輯的(test1.txt, test2.txt)
白底的是在 windows 7 底下使用記事本編輯的(test3.txt, test4.txt)
第一直行沒有空行,而第二直行多了一行空行
執行結果:
貌似 linux 建立的檔案會多讀一行?
我們先來看看 fgets 的函式說明:
char * fgets ( char * str, int num, FILE * stream );
//from http://www.cplusplus.com/reference/cstdio/fgets/
重點整理:
- 遇到下列任意情況時停止讀取:
- 讀到EOF
- 讀到'\n'
- 讀滿 (num - 1) 個字元 (剩下的一個位置須補上空字元 '\0')
- '\n' 也會讀進 str
- 讀到 EOF 後, feof(file) = 1
- 若僅讀到 EOF(無其他字元),回傳空指標,str 內容不變
若讀取錯誤亦回傳空指標, ferror(file) = 1 ,str 內容可能改變
若無以上兩種狀況,則回傳 str 指標
再來看看4個檔案用16進位表示時的狀況:
可以看到除了換行字元的差異外,vim 建立的檔案結尾時會自動補上 0a ,查閱ASCII表得知其為換行鍵,就是 '\n'
如果需要濾掉空行,可以這樣寫
- #include <stdio.h>
- #include <string.h>
- char* getstring(FILE* file, char* mem){
- int i;
- memset(mem, 0, 1000);
- while(mem[0] == '\0'){ // to test whether the line contains only '\n'
- if(!fgets(mem, 1000, file))
- return 0;
- else
- for(i = 0; i < 999; i++)
- if(mem[i] == '\n'){
- mem[i] = '\0'; // remove new line character
- break;
- }
- }
- return mem;
- }
- int main(void){
- char mem[1000] = {'\0'};
- FILE* file = fopen("test.txt", "r");
- if(!file){
- puts("cannot open file!");
- return 0;
- }
- if(getstring(file,mem)) // first line
- printf("%s",mem);
- while(getstring(file,mem)){
- printf("\n");
- printf("%s",mem);
- }
- return 0;
- }
如果只是要避免讀到空指標(在做字串處理時可能會出錯 Eg. strcmp)
將 fgets 放進 while 迴圈即可
程式碼如下
- #include <stdio.h>
- #include <string.h>
- int main(void){
- char mem[1000] = {'\0'};
- FILE* file = fopen("test.txt", "r");
- if(!file){
- puts("cannot open file!");
- return 0;
- }
- while(fgets(mem, sizeof(mem), file)){
- printf("%s", mem);
- memset(mem, 0, sizeof(mem));
- }
- return 0;
- }
沒有留言:
張貼留言