《C和指针》读书笔记第一章快速上手
寫在前面,由于學過C語言,導致想要跳躍式地翻閱《C和指針》,后來發現這實為錯誤,對于這本經典著作,要做的是從頭到尾保持體系的完整性。
《C和指針》配套代碼請移步網站:Pointers on C
作者的個人網站:Kenneth A. Reek
文章目錄
- 1.1 簡介
- 1.1.1 空白和注釋
- 1.1.2 預處理指令
- 1.1.3 main函數
- 1.1.4 read_column_numbers函數
- 1.1.5 rearrange 函數
- 1.2補充說明
- 1.3 警告的總結
- 1.4 編程提示的總結
1.1 簡介
我們所要分析的這個程序從標準輸入讀取文本并對其進行修改,然后把它寫到標準輸出。該程序首先讀取一串列標號。這些列標號成對出現,表示輸入行的列范圍。這串列標號以一個負值結尾,作為結束標志。剩余的輸入行被程序讀入并打印,然后輸入行中被選中范圍的字符串被提取出來并打印。注意,每行第一列的列標號為0.
這個程序的重要性在于它展示了當你開始編寫C語言程序時所需要知道的絕大多數基本技巧。
所以,本文就是對下面的程序從頭到尾、詳細的解釋和分析。
程序運行結果
4 9 12 20 -1 111111111a11bbbbbbbb1 adffdfsdf Original input : 111111111a11bbbbbbbb1 adffdfsdf Rearranged line: 11111abbbbbbbb1 how are you ,my friend Original input : how are you ,my friend Rearranged line: are yo,my frien see you Original input : see you Rearranged line: you bye Original input : bye Rearranged line:源代碼
/* ** This program reads input lines from the standard input and prints ** each input line, followed by just some portions of the lines, to ** the standard output. ** ** The first input is a list of column numbers, which ends with a ** negative number. The column numbers are paired and specify ** ranges of columns from the input line that are to be printed. ** For example, 0 3 10 12 -1 indicates that only columns 0 through 3 ** and columns 10 through 12 will be printed. */#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_COLS 20 /* max # of columns to process 所能處理的最大列號*/ #define MAX_INPUT 1000 /* max len of input & output lines每個輸入行/輸出行的最大長度 */int read_column_numbers( int columns[], int max ); void rearrange( char *output, char const *input,int n_columns, int const columns[] );int main( void ) {int n_columns; /* # of columns to process 進行處理的列標號*/int columns[MAX_COLS]; /* the columns to process 需要處理的列數*/char input[MAX_INPUT]; /* array for input line */char output[MAX_INPUT]; /* array for output line *//*** Read the list of column numbers 讀取該串列標號*/n_columns = read_column_numbers( columns, MAX_COLS );/*** Read, process and print the remaining lines of input.讀取、處理和打印剩余的輸入行*/while( gets( input ) != NULL ){printf( "Original input : %s\n", input );rearrange( output, input, n_columns, columns );printf( "Rearranged line: %s\n", output );}return EXIT_SUCCESS; }/* ** Read the list of column numbers, ignoring any beyond the specified ** maximum. */ int read_column_numbers( int columns[], int max ) {int num = 0;int ch;/*** Get the numbers, stopping at eof or when a number is < 0.*/while( num < max && scanf( "%d", &columns[num] ) == 1&& columns[num] >= 0 )num += 1;/*** Make sure we have an even number of inputs, as they are** supposed to be paired.*/if( num % 2 != 0 ){puts( "Last column number is not paired." );exit( EXIT_FAILURE );}/*** Discard the rest of the line that contained the final** number. 丟棄該行中包含最后一個數的那部分內容*/while( (ch = getchar()) != EOF && ch != '\n' );return num; }/* ** Process a line of input by concatenating the characters from ** the indicated columns. The output line is then NUL terminated. 處理輸入行,將指定列的字符連接在一起,輸出行以NUL結尾 */ void rearrange( char *output, char const *input,int n_columns, int const columns[] ) {int col; /* subscript for columns array columns數組的下標*/int output_col; /* output column counter 輸出列計數器*/int len; /* length of input line 輸入行的長度*/len = strlen( input );output_col = 0;/*** Process each pair of column numbers.處理每對列標號*/for( col = 0; col < n_columns; col += 2 ){int nchars = columns[col + 1] - columns[col] + 1;//每次兩個坐標中間包含的元素個數/*** If the input line isn't this long or the output** array is full, we're done.*/if( columns[col] >= len ||output_col == MAX_INPUT - 1 )break;/*** If there isn't room in the output array, only copy** what will fit.*/if( output_col + nchars > MAX_INPUT - 1 )nchars = MAX_INPUT - output_col - 1;/*** Copy the relevant data.復制相關的數據*/strncpy( output + output_col, input + columns[col],nchars );output_col += nchars;}output[output_col] = '\0'; }1.1.1 空白和注釋
首先需要注意的是程序的空白:空行將程序的不同部分分隔開來;制表符(tab)用于縮進語句,更好地顯示程序的結構等等。
清晰地顯示程序的結構固然重要,但告訴讀者程序能做些什么以及怎樣做則更為重要。注釋(comment)就是用于實現這個功能。
注釋以/*開始,以 * /結束。在C程序中,凡是可以插入空白的地方都可以插入注釋。然而,注釋不能嵌套,也就是說,第一個/ * 符號和第一個 * / 符號之間的內容都被看作是注釋,不管里面還有多少個/**/符號。
在C語言中,想要注釋掉代碼用/**/可不是一個好主意,如果試圖在一段代碼的首位分別加上/*和 */來注釋掉這段代碼,你不一定能如愿。如果這段代碼內部原先就有注釋存在,這樣做就會出問題。 要從邏輯上刪除一段C代碼,更好的辦法是使用#if 指令。只要像下面這樣使用:
#if 0statements #endif在#if 和#endif之間的程序段就可以有效地從程序中去除,即使這段代碼之間原先存在注釋也無妨,所以這是一種更為安全的方法。
1.1.2 預處理指令
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MAX_COLS 20 #define MAX_INPUT 1000這5行稱為預處理指令(preprocessor directives),因為它們是由預處理器解釋的。預處理器讀入源代碼,根據預處理指令對其進行修改,然后把修改過的源代碼遞交給編譯器。
在我們的例子中,預處理器用名為stdio.h的庫函數頭文件的內容替換第一條#include 指令語句,其結果仿佛是stdio.h的內容被逐字寫到源文件的那個位置。
stdio.h頭文件使我們可以訪問標準I/O庫中的函數,這組函數用于執行輸入和輸出。stdlib.h定義了EXIT_SUCCESS和EXIT_FAILURE符號。我們需要string.h頭文件提供的函數來操縱字符串。
提示: 如果你有有些聲明需要用于幾個不同的源文件,這個技巧也是一種方便的方法-----你在一個單獨的文件中編寫這些聲明,然后用#include指令把這個文件包含到需要使用這些聲明的源文件中。這樣,你就只需要這些聲明的一份拷貝,用不著在許多不同地方進行復制,避免了在維護這些代碼時出現錯誤的可能性。
int read_column_numbers( int columns[], int max ); void rearrange( char *output, char const *input,int n_columns, int const columns[] );這些聲明被稱為函數原型(function prototype)。它們告訴編譯器這些以后將在源文件中定義的函數的特征。這樣,當這些函數被調用時,編譯器就會對它們進行準確性檢查。每個原型以一個類型名開頭,表示函數返回值的類型。跟在返回類型后面的是函數名,再后面是函數期望接受 的參數。所以,函數read_column_numbers返回一個整數,接受兩個類型分別是整型數組和整形標量的參數。函數原型中參數的名字并非必需。
rearrange函數接收4個參數。其中第1個和第2個參數都是指針(pointer)。指針指定一個存儲于計算機內存中的值的地址,類似于門牌號碼指定某個特定的家庭位于街道的何處。第2個和第4個參數被聲明為const,這表示函數將不會修改函數調用者所傳遞的這兩個參數。關鍵字void表示函數并不返回任何值,在其他語言中,這種無返回值的函數被稱為過程(procedure)。
提示:假如這個程序的源代碼由幾個源文件所組成,那么使用該函數的源文件都必須寫明該函數的原型。把原型放在頭文件中并使用#include 指令包含它們,可以避免由于同一個聲明的多份拷貝而導致的維護性問題。
1.1.3 main函數
int n_columns; /* # of columns to process */int columns[MAX_COLS]; /* the columns to process */char input[MAX_INPUT]; /* array for input line */char output[MAX_INPUT]; /* array for output line */這幾行聲明了4個變量:一個整型標量,一個整型數組以及兩個字符數組。所有4個變量都是main函數的局部變量,其他函數不能根據它們的名字訪問它們。當然,它們可以作為參數傳遞給其他函數。
n_columns = read_column_numbers( columns, MAX_COLS );這條語句調用函數read_column_numbers。數組columns和MAX_COLS所代表的常量(20)作為參數傳遞給這個函數。在C語言中,數組參數是以引用(reference)形式進行傳遞的,也就是傳址調用,而標量和常量則是按值(value)傳遞的.在函數中對標量參數的任何修改都會在函數返回時丟失,因此,被調用函數無法修改調用函數以傳值形式傳遞給它的參數。然而,當被調用函數修改數組參數的其中一個元素時,調用函數所傳遞的數組就會被實際地修改。
事實上,關于C函數的參數傳遞規則可以表述如下:
所有傳遞給函數的參數都是按值傳遞的.
但是,當數組名作為參數時就會產生按引用傳遞的效果.如上所示,規則和現實行為之間似乎存在明顯的矛盾之處,后面將會做出解釋.
/*** Read, process and print the remaining lines of input.*/while( gets( input ) != NULL ){printf( "Original input : %s\n", input );rearrange( output, input, n_columns, columns );printf( "Rearranged line: %s\n", output );}用于描述這段代碼的注釋看上去似乎有些多余.但是,如今軟件開銷的最大之處并非在于編寫,而是在于維護.在修改一段代碼時所遇到的第一個問題就是要搞清楚這段代碼的功能.所以,如果你在代碼中插入一些東西,能使其他人在以后更容易理解它,那就非常值得這樣做.
這個循環代表了這個程序的主要邏輯.簡而言之,它表示:
while 我們還可以讀取另一行輸入時打印輸入行對輸入行進行重新整理,把它存儲于output數組打印輸出結果gets函數從標準輸入讀取一行文本并把它存儲于(作為參數傳遞給)數組中.一行輸入由一串字符組成,以一個換行符(newline)結尾.gets函數丟失換行符,并在該行的末尾存儲一個NUL字節(一個NUL字節是指字節模式為全0的字節,類似’\0’這樣的字符常量).然后,gets函數返回一個非NULL值,表示改行已被成功讀取。當gets函數被調用但事實上不存在輸入行時,它就返回NULL值,表示它到達了輸入的末尾(文件尾)。
補充:NUL是ASCII字符集中’\0’字符的名字,它的字節模式為全0.NULL指一個其值為0的指針.它們都是整型值,其值也相同,所以它們可以互換使用.然而,你還是應該使用恰當的常量,因為它能告訴閱讀程序的人不僅使用0這個值,而且告訴他使用這個值的目的.
符號NULL在頭文件stdio.h中定義.另一方面,并不存在預定義的符號NUL,所以如果你想使用它而不是字符常量’\0’,你必須自行定義.
在C程序中,處理字符串是常見的任務之一。盡管C語言并不存在“string”數據類型,但在整個語言中,存在一項約定:字符串就是一串以NUL字節結尾的字符。NUL是作為字符串終止符,它本身并不被看作是字符串的一部分。字符串常量(string literal)就是源程序中被雙引號括起來的一串字符。例如,字符串常量:“Hello”在內存中占據6個字節的空間,按順序分別是H,e,l,l,o和NUL。
printf函數執行格式化的輸出。C語言的格式化輸出比較簡單,printf函數接收多個參數,其中第一個參數是一個字符串,描述輸出的格式,剩余的參數就是需要打印的值。格式常常以字符串常量的形式出現。
格式字符串包含指定符(格式代碼)以及一些普通字符。這些普通字符將按照原樣逐字打印出來,但每個格式指定符將后續參數的值按照它所指定的格式打印。
| %d | 以十進制形式打印一個整數值 |
| %o | 以八進制形式打印一個整數值 |
| %x | 以十六進制形式打印一個整數值 |
| %g | 打印一個浮點值 |
| %c | 打印一個字符 |
| %s | 打印一個字符串 |
| \n | 換行 |
如果數組input包含字符串Hi, friend! 那么下面這條語句
printf("Original input: %s\n",input);的打印結果是:Original input : Hi,friend!后面以一個換行符終止。
例子程序接下來的一條語句是rearrange:
rearrange( output, input, n_columns, columns );后面3個參數是傳遞給函數的值,第1個參數則是函數將要創建并返回給main函數的答案。記住,這種參數是唯一可以返回答案的辦法,因為它是一個數組。最后一個printf函數顯示輸入行重新整理后的結果。
最后,當循環結束時,main函數返回值EXIT_SUCCESS.該值向操作系統提示程序成功執行。
1.1.4 read_column_numbers函數
** Read the list of column numbers, ignoring any beyond the specified ** maximum. */ int read_column_numbers( int columns[], int max ) {這幾行構成了read_column_numbers函數的起始部分。注意,這個聲明和早先出現在程序中的該函數原型的參數個數和類型以及函數的返回值完全匹配。如果出現不匹配的情況,編譯器就會報錯。
在函數聲明的數組參數中,并未指定數組的長度。這種格式是正確的,因為不論調用函數的程序傳遞給它的數組參數的長度是多少,這個函數都將照收無誤。這是一個偉大的特性,它允許單個函數操縱任意長度的一維數組。這個特性的不利一面是函數沒法知道 該數組的長度。如果確實需要數組的長度,它的值必須作為一個單獨的參數傳遞給函數。
當本例的read_column_numbers函數被調用時,傳遞給函數的其中一個參數的名字碰巧與上面給出的形參名字相同。但是,其余幾個參數的名字與對應的形參名字并不相同。和絕大多數語言一樣,C語言中形式參數的名字和實際參數的名字并沒有什么關系??梢宰寖烧呦嗤?#xff0c;但這并不是必須。
int num=0; int ch;這里聲明了兩個變量,它們時該函數的局部變量。第1個變量在聲明時被初始化為0,但第2個變量并未初始化。更準確地說,它的初始值將是一個不可預料的值,也就是垃圾。在這個函數里,它沒有初始值并不礙事,因為函數對這個變量所執行的第1個操作就是對它賦值。
/*** Get the numbers, stopping at eof or when a number is < 0.*/while( num < max && scanf( "%d", &columns[num] ) == 1&& columns[num] >= 0 )num += 1;這又是一個循環,用于讀取列標號。scanf函數從標準輸入讀取字符并根據格式字符串對它們進行轉換-----類似于printf函數的逆操作。scanf函數接受幾個參數,其中第一個參數是一個格式字符串,用于描述期望的輸入類型。剩余幾個參數都是變量,用于存儲函數所讀取的輸入數據。scanf函數的返回值是函數成功轉換并存儲于參數中的值的個數。
警告:對于這個函數,你必須小心在一,理由有二。首先,由于scanf函數的實現原理,所有標量參數的前面需要加上“&”符號。數組參數前面不需要加上“&”符號。但是,數組參數中如果出現了下標引用,也就是說實際參數是數組的某個特定元素,那么它的前面也必須加上一個“&”符號。
警告:第二個需要注意的地方是格式代碼,它與printf函數的格式代碼頗為相似卻又并不完全相同,所以很容易引起混淆。下表列出了一些你可能會在scanf函數中用到的格式代碼。注意,前5個格式代碼用于讀取標量值,所以變量參數的前面必須加上“&”符號。使用所有格式碼(除%c之外)時,輸入值之前的空白(空格、制表符、換行符等)會被跳過,值后面的空白表示該值的結束。因此,用%s格式碼輸入字符串時,中間不能包含空白。
| %d | 讀取一個整型值 | int |
| %ld | 讀取一個長整型值 | long |
| %f | 讀取一個實型值(浮點數) | float |
| %lf | 讀取一個雙精度實型值 | double |
| %c | 讀取一個字符 | char |
| %s | 從輸入中讀取一個字符串 | char型數組 |
我們現在可以解釋表達式:
scanf("%d",&columns[num])格式碼%d表示需要讀取一個整型值。字符是從標準輸入讀取,前導空白將被跳過。然后這些數字被轉換為一個整數,結果存儲于指定的數組元素中。我們需要在參數前加上一個“&”符號,因為數組下標選擇的是一個單一的數組元素,它是一個標量。
while循環的測試條件由3部分組成:
num<max
這個測試條件確保函數不會讀取過多的值,從而導致數組溢出。如果scanf函數轉換了一個整數之后,它就會返回1這個值。最后 columns[num]>=0 這個表達式確保函數所讀取的值是正數。如果3個測試條件之一的值為假,循環就會終止。
提示:標準并未硬性規定C編譯器對數組下標的有效性進行檢查,而且絕大多數C編譯器確實也不進行檢查。因此,如果你需要進行數組下標的有效性檢查,你必須自行編寫代碼。如果此處不進行num<max這個測試,而且程序所讀取的文件包含超過20個列標號,那么多出來的值就會存儲在緊隨數組之后的內存位置,這樣就會破壞原先存儲在這個位置的數據,可能是其他變量,也可以是函數的返回地址。這可能會導致多種結果,程序很可能不會按照你預想的那樣運行。
scanf函數每次調用時都從標準輸入讀取一個十進制整數。如果轉換失敗,不管是因為文件已經讀完還是因為下一次輸入的字符無法轉換為整數,函數都會返回0,這樣就會使整個循環終止。如果輸入的字符可以合法地轉換為整數,那么這個值就會轉換為二進制數存儲于數組元素columns[num]中,然后scanf就返回1.(再重提一下:scanf返回的是正確讀入的個數;如果到了文件尾,返回EOF)
/*** Make sure we have an even number of inputs, as they are** supposed to be paired.*/if( num % 2 != 0 ){puts( "Last column number is not paired." );exit( EXIT_FAILURE );}這個測試檢查程序所讀取的整數是否為偶數個,這是程序規定的,因為這些數字要求成對出現。
puts函數是gets函數的輸出版本,它把指定的字符串寫到標準輸出并在末尾添上一個換行符。
程序接著調用exit函數,終止程序的運行,EXIT_FAILURE這個值被返回給操作系統,提示出現了錯誤。
/*** Discard the rest of the line that contained the final** number.*/while( (ch = getchar()) != EOF && ch != '\n' );當scanf函數對輸入值進行轉換時,它只讀取需要讀取的字符。這樣,該輸入行包含了最后一個值的剩余部分仍會留在那里,等待被讀取。它可能只包含作為終止符的換行符,也可能包含其他字符。不論如何,while循環將讀取并丟棄這些剩余的字符,防止它們被解釋為第1行數據。
下面這個表達式值得花點時間討論。
(ch = getchar()) != EOF && ch != '\n'首先,getchar函數從標準輸入讀取一個字符并返回它的值。如果輸入中不再存在任何字符,函數就會返回常量EOF(在stdio.h中定義),用于提示文件的結尾。
從getchar函數返回的值被賦給變量ch,然后把它與EOF進行比較。在賦值表達式兩端加上括號用于確保賦值操作先于比較操作進行。如果ch等于EOF,整個表達式的值就為假,循環將終止。若非如此,再把ch與換行符相比較,如果兩者相等,循環也將終止。因此,只有當輸入尚未到達文件尾并且輸入的字符并非換行符時,表達式的值才是真的(循環將繼續進行)。這樣,這個循環就能剔除當前輸入行最后的剩余字符。
現在讓我們進入有趣的部分。 在大多數編程語言中,我們將像下面這樣編寫循環:
ch=getchar(); while(ch!=EOF&& ch!='\n')ch=getchar();它將讀取一個字符,接下來如果我們尚未到達文件的末尾或讀取的字符并不是換行符,它將繼續讀取下一個字符。注意這里兩次出現了下面這條語句:
ch=getchar();C語言可以把賦值操作蘊含于while循環內部,這樣就允許程序員消除冗余語句。
提示:例子程序中的那個循環的功能和上面這個循環相同,但它包含的語句要少一些。無可爭議,這種形式可讀性差一些。但是,你之所以會覺得這種形式的代碼可讀性差,只是因為你對C語言及其編程的習慣用法不熟之故。經驗豐富的C程序員在閱讀和編寫這類語句時根本不會出現困難。在這種變成習慣用法中,同樣的語句少寫一次帶來的維護方面的好處更大一些。
一個經常問到的問題是:為什么ch被聲明為整型,而我們事實上需要它來讀取字符? 答案是EOF是一個整型值,它的位數也比字符類型要多,把ch聲明為整型可以防止從輸入讀取的字符意外地被解析為EOF。但同時,這也意味著接收字符的ch必須足夠大,足以容納EOF,這就是ch使用整型值的原因。字符只是小整型數而已,所以用一個整型變量容納字符值并不會引起任何問題。
1.1.5 rearrange 函數
/* ** Process a line of input by concatenating the characters from ** the indicated columns. The output line is then NUL terminated. */ void rearrange( char *output, char const *input,int n_columns, int const columns[] ) {int col; /* subscript for columns array */int output_col; /* output column counter */int len; /* length of input line */這些語句定義了rearrange函數并聲明了一些局部變量。此外最有趣的一點:前兩個參數被聲明為指針,但在函數實際調用時,傳給它們的參數確實數組名。當數組名作為實參時,傳給參數的實際上是一個指向數組起始位置的指針,也就是數組在內存中的地址。 正因為實際傳遞的是一個指針而不是一份數組的拷貝,才使數組名作為參數時具備了傳址調用的語義。函數可以按照操縱指針的方式來操縱實參,也可以像使用數組名一樣用下標來引用數組的元素。
但是,由于它的傳址調用語義,如果函數修改了形參數組的元素,它實際上將修改實參數組的對應元素。因此,例子程序把columns聲明為const就有兩方面的作用。首先,它聲明該函數的作者的意圖是這個參數不能被修改。其次,它導致編譯器去驗證是否違背該意圖。因此,這個函數的調用者不必擔心例子程序作為第4個參數傳遞給函數的數組中的元素會被修改。
len = strlen( input );output_col = 0;/*** Process each pair of column numbers.*/for( col = 0; col < n_columns; col += 2 ){這個函數的真正工作從這里開始。我們首先獲得輸入字符串的長度,這樣如果列標號超出了輸入行的范圍,我們就忽略它。C語言的for語句跟它在其他語言中不太像,它更像是while語句的一種常用風格的簡寫法。for語句包含3個表達式(順表說一下,這3個表達式都是可選的)。第一個表達式是初始部分,它只在循環開始前執行一次。第二個表達式是測試部分,它在循環每執行一次后都要執行一次。第三個表達式是調整部分,它在每次循環執行完畢后都要執行一次,但它在測試之前執行。
上面這個for循環可以改寫為如下所示的while循環
col=0; while(col<n_columns){循環體col+=2; }看for循環里面做了啥
int nchars = columns[col + 1] - columns[col] + 1;/*** If the input line isn't this long or the output** array is full, we're done.*/if( columns[col] >= len ||output_col == MAX_INPUT - 1 )break;/*** If there isn't room in the output array, only copy** what will fit.*/if( output_col + nchars > MAX_INPUT - 1 )nchars = MAX_INPUT - output_col - 1;/*** Copy the relevant data.*/strncpy( output + output_col, input + columns[col],nchars );output_col += nchars;這是for循環的循環體,它一開始計算當前列范圍內字符的個數,然后決定是否繼續進行循環。如果輸入行比起始列短,或者輸出行滿,它便不再執行任務,使用break語句立即退出循環。
接下來的一個測試檢查這個范圍內的所有字符是否都能放入輸出行中,入宮不行,它就把nchars調整為數組能夠容納的大小。
最后,strncpy函數把選中的字符從輸入行復制到輸出行中可用的下一個位置。strncpy函數的前兩個參數分別是目標字符串和源字符串的地址。在這個調用中,目標字符串的位置是輸出數組的起始地址向后偏移output_col列的地址,源字符串的位置則是輸入數組起始地址向后偏移columns[col]個位置的地址。第3個參數指定需要復制的字符數。輸出列計數器隨后向后移動nchars個位置。
}output[output_col] = '\0'; }循環結束之后,輸出字符串將以一個NUL字符作為終止符。注意,在循環體中,函數經過精心設計,確保數組仍有空間容納這個終止符。然后,程序執行流表到達了函數的末尾,于是執行一條隱式的return語句。由于不存在顯示的return語句,所以沒有任何值返回給調用這個函數的表達式。
1.2補充說明
本章的例子描述了許多C語言的基礎知識。在親自動手編寫程序之前,還應該知道一些東西。首先是putchar函數,它與getchar函數相對應,它接受一個整型參數,并在標準輸出中打印該字符(如前所述,字符在本質上也是整型)。
同時,在函數庫中存在許多操縱字符串的函數。這里我將簡單地介紹幾個最有用的。除非特別說明,這些函數的參數既可以是字符串常量,也可以是字符型數組名,還可以是一個指向字符的指針。
strcpy和strncpy函數類似,但它沒有限制需要復制的字符數量。它接受兩個參數:第2個字符串參數將被復制到第1個字符串參數,第1個字符串原有的字符將被覆蓋。strcat函數也接受兩個參數,但它把第2個字符串參數添加到第1個字符串參數的末尾。在這兩個函數中,它們的第1個字符串參數不能是字符串常量。而且,確保目標字符串有足夠的空間是程序員的責任,函數并不對其進行檢查。
在字符串內進行搜索的函數是strchr,它接受兩個參數,第1個參數是字符串,第2個參數是一個字符。這個函數在字符串參數內搜索字符參數第1次出現的位置,如果搜索成功就返回指向這個位置的指針,如果搜索失敗就返回一個NULL指針。strstr函數的功能類似,但它的第2個參數也是一個字符串,它搜索第2個字符串在第1個字符串中第1次出現的位置。
1.3 警告的總結
1.4 編程提示的總結
1.使用#include指令避免重復聲明
2.使用#define指令給常量值取名
3.在#include文件中放置函數原型
4.在使用下標前先檢驗它們的值
5.在while或if表達式中蘊含賦值操作
6 如何編寫一個空循環體
7始終要進行檢查,確保數組不越界
總結
以上是生活随笔為你收集整理的《C和指针》读书笔记第一章快速上手的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 福满一生几年拿回本金
- 下一篇: win10中cmd如何编译和运行c/c+