日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

21天学通c语言总结(3)

發(fā)布時(shí)間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 21天学通c语言总结(3) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第15天:有關(guān)指針的高級(jí)用法

指向指針的指針

int multi[3][4]; int (*ptr)[4]; int *p; p = (int *)ptr;

上面multi是一個(gè)指針指向multi[0],multi[0]也是一個(gè)指針指向multi[0][0]。
ptr是一個(gè)能指向包含4個(gè)int變量的數(shù)組的指針變量,數(shù)組指針。必須用圓括號(hào)否則聲明的是指針數(shù)組,因?yàn)殚g接運(yùn)算符的優(yōu)先級(jí)低于[]。
(int *)是強(qiáng)制類型轉(zhuǎn)換,暫時(shí)將ptr的數(shù)據(jù)類型從聲明的類型轉(zhuǎn)換為新的類型。

指針數(shù)組

char *mes[20];
將指針數(shù)組傳遞給函數(shù):
void pfs(char *p[], int n);
void pfs(char **p, int n);
上面兩個(gè)均可以傳遞指針數(shù)組,實(shí)際上傳遞的是指向指針的指針。
int指針數(shù)組,int *p[4]; p[0]+1;的內(nèi)容并不是p[1]而是p[0]所表示的地址加上4個(gè)字節(jié)。

malloc()默認(rèn)返回void類型的指針。前面加(char *)強(qiáng)制轉(zhuǎn)換。

函數(shù)指針

type (*ptr_to_func)(paremeter_list);
*ptr_to_func加括號(hào)是因?yàn)?*的優(yōu)先級(jí)小于()。如果不加則定義的是返回指針的函數(shù)。
被指向函數(shù)的返回類型和參數(shù)列表必須和指針聲明的返回值和參數(shù)列表相同。
int square(int);
int (*ptr)(int);
ptr = square;

不帶括號(hào)的函數(shù)名是一個(gè)指向函數(shù)的指針常量。

  • 聲明函數(shù)指針一定用圓括號(hào);
  • 不要將函數(shù)指針指向返回類型和參數(shù)列表不匹配的函數(shù)。

鏈表

鏈表中的數(shù)據(jù)被存儲(chǔ)在結(jié)構(gòu)中。

struct person{ char name[20]; struct person *next; };

組成鏈表的結(jié)構(gòu)可稱為鏈接、節(jié)點(diǎn)或元素。
最后一個(gè)節(jié)點(diǎn)的next指針為NULL,頭指針(非結(jié)構(gòu))指向第一個(gè)節(jié)點(diǎn)。

  • 節(jié)點(diǎn)加入開頭
  • new = (struct person*)malloc(sizeof(struct person)); new->next = head; head = new; //如果先賦值頭指針,鏈表丟失
  • 節(jié)點(diǎn)添加至末尾
  • struct person *current; current = head; while (current-> != NULL)current = current->next; new = (struct person)malloc(sizeof(struct person)); current->next = new; new->next = NULL;
  • 節(jié)點(diǎn)添加至中間
  • struct person *marker; // desired location ... new = (...)malloc(...); new->next = marker->next; marker->next = new;
  • 刪除節(jié)點(diǎn)
  • //刪除第一個(gè) struct person *p; p = head->next; free(head); head = p; //刪除最后一個(gè) s.. person *c1, *c2; c1 = head; c2 = head->next; while (c2->next != NULL) {c1 = c2;c2 = c1->next; } free(c2); c1->next = null; if (head = c1)head = null; //刪除中間節(jié)點(diǎn) s.. person *c1, *c2; c2 = c1->next; c2 = c2->next; free(c1->next); c1->next = c2;

    刪除后節(jié)點(diǎn)仍然在內(nèi)存中,但是不在鏈表中,實(shí)際程序應(yīng)歸還被刪除節(jié)點(diǎn)占用的內(nèi)存,仍然通過(guò)free()完成,見第20天。

    總結(jié)

    • 數(shù)組指針
    • 指針數(shù)組(指向指針的指針),更方便處理字符串。
    • 函數(shù)指針。
    • 鏈表。

    第16天:使用磁盤文件

    磁盤文件

    • 文本流與文本模式文件關(guān)聯(lián)
    • 二進(jìn)制流與二進(jìn)制模式相關(guān)聯(lián)

    c文件路徑名:
    c:\\data\\list.txt;

    打開文件

    FILE *fopen(const char *filename, const char *mode);
    讀取前聲明文件指針,FILE是stdio.h中定義的結(jié)構(gòu),調(diào)用fopen時(shí)創(chuàng)建FILE實(shí)例,成功則返回指向該實(shí)例的指針,失敗返回NULL
    打開模式mode:

    • r:只讀,不存在返回NULL
    • w:只寫,不存在創(chuàng)建,存在則刪除后創(chuàng)建
    • a:附加,不存在創(chuàng)建,存在追加到末尾
    • r+:讀寫,不存在創(chuàng)建,存在寫在文件開頭,覆蓋原數(shù)據(jù)
    • w+:讀寫,不-------建,存在則覆蓋
    • a+:讀寫,---------建,存在則追加到末尾

    默認(rèn)為文本模式,以二進(jìn)制打開在模式后加上b,rb,wb,ab等。
    使用fopen()時(shí),一定要檢查是否出錯(cuò)

    讀寫文件數(shù)據(jù)

    三種方式

    • 格式化輸出,只能用于文本文件,主要供其他文件讀取。
    • 字符輸出,主要用于文本文件。
    • 直接輸出(direct output),將內(nèi)存的內(nèi)容直接保存到磁盤文件,只適用于二進(jìn)制文件,供c程序使用。

    讀取時(shí)也是類似三種。
    上面的規(guī)則并非不可逾越。

    格式化輸入/輸出

  • 格式化輸出
  • int fprintf(FILE *fp, char *fmt, ...);
    fprintf與printf區(qū)別只是前者可以指定流,如果指定stdout則沒有區(qū)別。

  • 格式化輸入
  • int fscanf(FILE *fp, const char *fmt, ...);
    與scanf的差別也僅是指定流。

    字符輸入/輸出

  • 字符輸入
  • getc(),fgetc()。這兩個(gè)函數(shù)相同,成功返回讀取的字符,失敗返回EOF(-1)
    int getc(FILE *fp);
    返回int是因?yàn)?#xff0c;讀取文件時(shí)必須讀取文件尾標(biāo)記,而有些系統(tǒng)標(biāo)記為int,而不是char。

    fgets(),char *fgets(char *str, int n, FILE *fp); str是指向緩沖區(qū)的指針,n(讀n-1個(gè),最后加空字符)是要讀取的最大字符數(shù),fp是FILE指針,由fopen返回的。
    失敗返回NULL。

  • 字符輸出
  • putc(),fputc()。int putc(int ch, FILE *fp); 將一個(gè)字符寫入流,成功返回字符,失敗返回EOF。

    fputs()。char fputs(char *str, FILE *fp); 與puts的差別,可以指定流,不會(huì)在末尾加換行符。

    直接輸入/輸出

  • fwrite()
    int fwrite(void *buf, int size, int count, FILE *fp);
    buf是指向內(nèi)存區(qū)域的指針(任何類型),size指定每項(xiàng)數(shù)據(jù)的長(zhǎng)度(字節(jié)),count數(shù)據(jù)項(xiàng)數(shù)。
    成功返回count,失敗返回小于count的數(shù)。
    struct adress data[50];寫入文件,可以:
    fwrite(data, sizeof(adress), 50, fp);或fwrite(data, sizeof(data), 1, fp);二者等價(jià)。

  • fread()
    int fread(void *buf, int size, int count, FILE *fp);
    用法類似fwrite()。但使用fread時(shí)要小心,明確數(shù)據(jù)類型,否則中不會(huì)報(bào)錯(cuò)但結(jié)果錯(cuò)誤。

  • 文件緩沖技術(shù):關(guān)閉和刷新文件

    int fclose(FILE *fp); fp是與流相關(guān)聯(lián)的FILE指針,成功返回0,失敗-1,關(guān)閉時(shí)刷新文件的緩沖區(qū)(寫入文件中)。
    void fcloseall(void);刷新所有的流緩沖區(qū)(標(biāo)準(zhǔn)流之外),返回關(guān)閉的流。(不是返回void么)。除非要關(guān)閉所有的流,否則不要用fcloseall()。

    也可以不關(guān)閉流刷新緩沖區(qū),int fflush(FILE *fp);,不想關(guān)閉文件同時(shí)想將文件緩沖區(qū)的內(nèi)容寫入時(shí)使用,成功返回0,失敗返回EOF。int flushall(void);,需要刷新所有打開的流的緩沖區(qū)時(shí)使用,返回打開的流的數(shù)目。

    順序文件存取和隨機(jī)文件存取

    每個(gè)打開的文件都有一個(gè)相應(yīng)的位置指示器。

  • ftell()和rewind()。
  • void rewind(FILE *fp);調(diào)用后指示器指向開頭(字節(jié)0)。
    long ftell(FILE *fp); 成功則返回當(dāng)前位置離開頭的字節(jié)數(shù),錯(cuò)誤返回-1L。

  • fseek()。
  • int fseek(FILE *fp, long offset, int origin);,調(diào)用后可以將位置指向任何位置,offset指定移動(dòng)的距離,origin指定相對(duì)什么的位置。
    origin可以是SEEK_SET表示0開始,SEEK_CUR表示1當(dāng)前,SEEK_END表示2末尾。成功返回0,錯(cuò)誤返回非0。
    if ( fseek(fp, (offset * sizeof(int)), SEEK_SET) != 0 )

    檢測(cè)文件尾

    文本文件:while((c = fgetc(fp)) != EOF),因?yàn)锳SCII碼都不為-1,當(dāng)讀入-1時(shí)可以斷定到末尾。
    二進(jìn)制文件及文本文件:int feof(FILE *fp);未到末尾返回0,否則返回非0。

    文件管理函數(shù)

  • 刪除文件
    int remove(const char *filename);,filename指向要?jiǎng)h除的文件,刪除成功返回0,不成功返回-1。

  • 重命名文件
    int rename(const char *oldname, const char *newname);,兩個(gè)文件必須位于相同的磁盤驅(qū)動(dòng)器,成功0,失敗-1。

  • 復(fù)制文件
    c語(yǔ)言沒有復(fù)制文件的庫(kù)函數(shù)。但因?yàn)閏使用流。因此自己編寫很簡(jiǎn)單。
    1.以二進(jìn)制rb讀,可以保證能夠復(fù)制任何文件,而不是僅僅是文本文件。
    2.二進(jìn)制wb模式打開目標(biāo)文件。
    3.fgetc()讀取一個(gè)字符,rb打開指示器在開頭,無(wú)需顯式的放置。
    4.feof()表明到結(jié)尾(非0),則關(guān)閉兩個(gè)文件,返回0。
    5.未到末尾,字符寫入目標(biāo)文件,回到3。

  • 臨時(shí)文件

    char *tmpnam(char *s);,用來(lái)創(chuàng)建有效且不與任何已有文件沖突的名稱。s指向的緩沖區(qū)必須足夠大。
    兩種方式創(chuàng)建臨時(shí)文件:
    1:char buffer[10], *c; tmpnam(buffer); // 傳遞指針
    2:c=tmpnam(NULL); //傳遞空指針
    一定要?jiǎng)h除臨時(shí)文件。remove(buffer); remove(c);

    第17天:操縱字符串

    • 確定長(zhǎng)度
      size_t strlen(char *str);返回字符串長(zhǎng)度,不包含空字符。
      size_t表示unsigned的型。

    • 復(fù)制字符串
      char *strcpy(char *destination, const char *source);,必須分配空間
      char *strncpy(char *destination, const char *source, size_t n);,復(fù)制前n個(gè)字符。小于n加上空字符,多于n不加空字符。
      char *strdup(char *source);不是ANSI標(biāo)準(zhǔn)函數(shù),調(diào)用時(shí)自動(dòng)調(diào)用malloc分配內(nèi)存。

    • 拼接字符串
      char *strcat(char *str1, const char *str2);
      char *strncat(char *str1, const char *str2, size_t n);

    • 比較字符串
      int strcmp(const char *str1, const char *str2);比較兩字符串直到出現(xiàn)不相同字符,相等0,小于<0,大于>0.
      int strcmp(const char *str1, const char *str2, size_t n);,一直比較直到不相等字符或比較了n個(gè)字符。

    • 查找字符串
      strchr(),strrchr()。查找字符第一次和最后一次出現(xiàn)的位置。
      strcspn(),strspn()。前者在一個(gè)字符串中查找另一個(gè)字符串的字符第一次出現(xiàn)的位置,找不到返回strlen(str1)。后者指出從str1開頭到什么位置之間所有的字符都包含在str2中。
      strpbrk(),類似strcspn,不同是返回指針,找不到返回null。

    最有用的strstr()。char *strstr(const char *str1, const char *str2);,查找一個(gè)字符串在另一個(gè)字符串中第一次出現(xiàn)的位置。返回位置指針。可以通過(guò)指針減法獲得離str1開頭的距離。

    • 字符串轉(zhuǎn)換
      char *strlwr(char *str); char *strupr(char *str);
      分別為將大寫轉(zhuǎn)換為小寫,和小寫->大寫。
      不是ANSI標(biāo)準(zhǔn)。

    • 其他字符串函數(shù)
      char *strrev(char *str); 逆序
      char *strset(char *str, int ch); 空字符外全改為ch.
      char *strnset(char *str, int ch, size_t n); 前n個(gè)改為ch.

    • 字符串轉(zhuǎn)數(shù)字
      atoi,atol,atof

    • 字符檢測(cè)函數(shù)
      isxxxx() ctype.h中定義的宏

    ANSI對(duì)大小寫轉(zhuǎn)換的支持:toupper(),tolower()。一次處理一個(gè)字符,利用返回值。ch = toupper(ch);而不是toupper(ch);

    總結(jié)

    這些庫(kù)函數(shù),返回指針的失敗后返回NULL,返回int的失敗返回EOF(-1),成功返回0。

    做練習(xí)時(shí)寫了一個(gè)查找文本中某字符串出現(xiàn)次數(shù)及出現(xiàn)在第幾行的程序,感覺挺有趣。。

    第18天:有關(guān)函數(shù)的高級(jí)主題

    將指針傳遞給函數(shù)

    傳遞方式有兩種:按值傳遞和按引用傳遞。
    前者不能修改參數(shù)值,通過(guò)返回值也只能修改一個(gè)參數(shù)。
    后者可以修改多個(gè)參數(shù)的值。定義時(shí)需要用*解除引用。

    void類型的指針

    指向任何對(duì)象,解除引用之前需要強(qiáng)制類型轉(zhuǎn)換。
    無(wú)法算數(shù)運(yùn)算。

    可變數(shù)目函數(shù)

    頭文件stdarg.h
    宏:va_list定義存取各參數(shù)的指針arg_ptr。
    va_start():初始化參數(shù)列表,將指針和最后一個(gè)固定參數(shù)傳遞給他。
    va_arg():依次取回各個(gè)參數(shù),并將指針指向下一個(gè)參數(shù),接受arg_ptr和下一個(gè)參數(shù)的類型。
    va_end():清理。
    至少要有一個(gè)固定參數(shù)。

    返回指針的函數(shù)

    不要和函數(shù)指針弄混。

    第19天:函數(shù)庫(kù)

    數(shù)學(xué)函數(shù)

    頭文件math.h
    三角函數(shù)sin(), cos(), tan(), asin(), acos(), atan(), atan2();
    指數(shù)對(duì)數(shù)exp(), log(), log10();
    雙曲cosh(), sinh(), tanh();
    求根sqrt()取整ceil(), floor();x的y次方pow(x, y);返回x/y的余數(shù)fmod(x, y);
    所有數(shù)學(xué)函數(shù) 返回值為double類型

    時(shí)間函數(shù)

    頭文件time.h
    兩種表示時(shí)間的方式:
    第一是記錄從1970年1月1日午夜開始過(guò)去的秒數(shù),負(fù)數(shù)表示之前的某時(shí)刻。
    第二是將其劃分為年月日等,使用結(jié)構(gòu)tm。

    處理時(shí)間

    時(shí)間函數(shù)的time_t和clock_t均為longlong型。

    • time_t time(time_t, *timeptr);返回自1970年的秒數(shù)。

      兩種調(diào)用形式:now = time(0); 或 time(&now);

    • struct tm *localtime(time_t *ptr); time_t mktime(struct tm *ntime);
      前者將time_t轉(zhuǎn)換成tm結(jié)構(gòu),后者將tm結(jié)構(gòu)轉(zhuǎn)換成time_t。

    • clock_t clock(void);返回程序從開始執(zhí)行起過(guò)去的時(shí)間。

    • 顯示時(shí)間char *asctime(struct tm *ptr);、 char *ctime(time_t *ptr);以及size_t strftime(char *s, size_t max, char *fmt, struct tm *ptr);
      第一個(gè)接受tm結(jié)構(gòu)作為參數(shù),第二個(gè)結(jié)構(gòu)time_t變量作為參數(shù),都返回如下格式:
      Thu Jun 13 10:22:23 1991
      第三個(gè)可以用格式化字符串的方式對(duì)時(shí)間的格式進(jìn)行格式化,常見的:
      %a,%A縮寫星期及完整星期。%b,%B縮寫月份及完整月份
      %D相當(dāng)于%m/%d/%y。%F相當(dāng)于%Y-%m-%d
      // 上面試了下不對(duì)。。
      H, M, S24小時(shí)制的時(shí)分秒。%T相當(dāng)于%H:%M:%S
      %U0-53表示的星期。%x日期如30-Jun-91。%X時(shí)間如10:41:50。
      strftime(buf1, 80, "the data is %D, week %U of year %Y.", ptr);
      put(buf1);

    處理錯(cuò)誤

  • void assert(int expression);
    如果expression為錯(cuò),則assert強(qiáng)行終止程序。
    可以定義#define NDEBUG使assert處于關(guān)閉狀態(tài)。

  • errno.h頭文件
    需要配合void perror(const char *msg);使用。

  • if ((fp = fopen(filename, "r")) == NULL){perror("you goofed!");printf("error = %d.\n", errno);exit(1);}

    查找和排序

    void qsort(void *base, size_t num, size_t size, int (* cmp)(const void *element1, const void *element2));

    void besearch(const void *key, void *base, size_t num, size_t width, int (* cmp)(const void *element1, const void *element2));

    前者升序排序,后者以二分法查找鍵值(要求數(shù)組升序)。
    key指向要查找的數(shù)據(jù)項(xiàng),base指向數(shù)組第一個(gè)元素,num是數(shù)組元素?cái)?shù),width(size)是每個(gè)元素的長(zhǎng)度,cmp是一個(gè)指向比較函數(shù)的指針。比較函數(shù)滿足:大于返回大于0,等于返回0,小于返回小于0。

    第20天:管理內(nèi)存

    類型轉(zhuǎn)換

    自動(dòng)轉(zhuǎn)換

    • 計(jì)算表達(dá)式時(shí)類型提升
      char<short<int<long<long long<float<double<long double

    • 賦值時(shí)轉(zhuǎn)換
      int i; float f; f = i;時(shí)i被提示為float。

    顯示轉(zhuǎn)換

    • 強(qiáng)制轉(zhuǎn)換算數(shù)表達(dá)式
      int i1 = 100, i2 = 40;
      f1 = (float)i1 / i2;
      計(jì)算時(shí)先把i1強(qiáng)制轉(zhuǎn)換,i2會(huì)自動(dòng)提升。
    • 裝換指針
      對(duì)void解除引用時(shí)必須將其轉(zhuǎn)換為相應(yīng)的類型。

    分配內(nèi)存空間

    • void *malloc(size_t num);

    • void *calloc(size_t num, size_t size);
      上面兩個(gè)類似,calloc分配時(shí)會(huì)自動(dòng)把內(nèi)存內(nèi)容設(shè)置為0。前者num指字節(jié)數(shù),后者num為對(duì)象數(shù),size為對(duì)象的大小(字節(jié))。

    • void *realloc(void *ptr, size_t size);
      改變分配內(nèi)存的大小,ptr為原來(lái)內(nèi)存的指針,size為新的大小。
      ptr為NULL,則類似于malloc()。size為0,則釋放內(nèi)存,返回NULL。

    • free()釋放內(nèi)存
      void free(void *ptr);

    操縱內(nèi)存塊

    • void *memset(void *dest, int c, size_t count);
      將指定的字節(jié)設(shè)置成特定的值。
      dest指向要初始化的內(nèi)存,c被視為char(0-255有效),count指定字節(jié)數(shù)。
      例如:memset(message + 2, '#', 10);

    • memcpy, void *memmove(void dest, void *src, size_t count);
      復(fù)制數(shù)據(jù)。
      前者處理重疊部分時(shí)會(huì)出錯(cuò),因此可以完全使用后者。例如 :
      memmove(temp + 6, temp + 4, 10);

    位的用法

  • 移位運(yùn)算
    y = x << 1;
    y = x >> 1;
    分別為左移右移,存在溢出現(xiàn)象。

  • 按位邏輯運(yùn)算符
    雙目運(yùn)算符。
    &, |, ^分別為:按位與,或,異或。

  • 求補(bǔ)(~):按位取反

  • 結(jié)構(gòu)中的位字段

  • struct emp_data {unsigned dental : 1;unsigned college : 1;unsigned health : 2;... };

    節(jié)省內(nèi)存空間,c中最小的數(shù)據(jù)類型為char,1字節(jié),存儲(chǔ)只需1-7位的數(shù)據(jù)時(shí)浪費(fèi)內(nèi)存。
    位字段必須放在結(jié)構(gòu)定義的最前面。賦值時(shí)采用符號(hào)變量TRUE、FALSE等最好,超過(guò)范圍時(shí)結(jié)果不可預(yù)測(cè)。

    • 將輸入轉(zhuǎn)換為二進(jìn)制時(shí),可以按位運(yùn)算或者不斷除以2求余。

    第21天:編譯器的高級(jí)用法

    多文件編譯

    之前知乎抄的vscode配置
    https://www.cnblogs.com/esllovesn/p/10012653.html這個(gè)是簡(jiǎn)化版也是更方便版的,建議直接看這個(gè)。
    https://www.zhihu.com/question/30315894這個(gè)是知乎原文,比較復(fù)雜。

    進(jìn)行少量的多文件編譯,C語(yǔ)言直接用gcc 源文件1.c 源文件2.c 頭文件1.h這樣就好,C++用g++。默認(rèn)生成a.exe,加-o可指定輸出文件名,其余選項(xiàng)百度gcc使用教程。如果需要多次編譯可以寫一個(gè)批處理。

    • 進(jìn)行大量的多文件編譯,請(qǐng)學(xué)習(xí)如何寫makefile或使用cmake。然后把tasks的命令改成調(diào)用make等。如果你想使用別人的庫(kù),比如ffmpeg,可能需要在命令中指定-I、-l(小寫的L)、-L。具體參數(shù)閱讀那個(gè)庫(kù)的文檔。還可能需要把路徑添加到c_cpp_properties.json和compile_flags.txt里來(lái)配置Intellisense。這些情況下可以考慮單獨(dú)建一個(gè)工作區(qū),不要和單文件編譯的共用。其實(shí)不新建工程(Project)、只是單文件就能調(diào)試,是不利于以后使用和理解大型IDE的。不過(guò)初學(xué)也不用掌握那么多,不要覺得建工程很麻煩、不建工程就能編譯很強(qiáng)就是了。總之這些和VSC無(wú)關(guān),用其它IDE或是手動(dòng)編譯也會(huì)遇到差不多的問(wèn)題,也有點(diǎn)復(fù)雜。

    入門水平,不太懂后面的意思,使用第一種少量多文件編譯的方法。

    .c文件–>預(yù)處理–>.i文件–>編譯–>.s文件–>匯編–>.o文件–>鏈接–>.exe文件

    gcc -E (E大寫)預(yù)處理(preprocessing)。不會(huì)檢查語(yǔ)法錯(cuò)誤。win10需要使用重新定向生成.i文件gcc -E test.c > test.i或者指定文件名gcc -E test.c -o test.i,否則只會(huì)輸出到stdout。

    gcc -S(S大寫)編譯(compiling)。將.i文件編譯成.s文件,即使不指定文件名也會(huì)生成與.i文件同名的.s文件,即gcc -S test.i -o test.s與gcc -S test.i相同。并且檢查語(yǔ)法錯(cuò)誤是在編譯過(guò)程進(jìn)行的

    gcc -c(c小寫)匯編(assembling),將.s文件轉(zhuǎn)換成機(jī)器能執(zhí)行的機(jī)器代碼.o文件,同樣即使不指定文件名也會(huì)生成與.s文件同名的.o文件,gcc -c test.s -o test.o與gcc -c test.s相同。

    gcc x.o或gcc x.o -o x.exe鏈接(linking)將機(jī)器碼.o文件連接成可執(zhí)行文件.exe。

    模塊化編程

    通用指導(dǎo)原則:

    • 輔助模塊(secondary module)應(yīng)包含通用的函數(shù),常見的做法是,對(duì)每一類函數(shù),創(chuàng)建一個(gè)輔助模塊。例如:鍵盤函數(shù)放在keyboard.c中,屏幕顯示函數(shù)放在screen.c中等。
    • 主模塊應(yīng)包含main()和其他程序特有的函數(shù)。
    • 每個(gè) 輔助模塊都有一個(gè)頭文件,名稱應(yīng)與相應(yīng)的模塊名相同,擴(kuò)展名為.h。應(yīng)包含(1).輔助模塊中的函數(shù)的原型。(2).定義模塊使用的宏和符號(hào)常量的#define編譯指令。(3).模塊使用的結(jié)構(gòu)和外部變量的定義。
    • 為防止頭文件被包含多次,可以使用預(yù)處理器來(lái)實(shí)現(xiàn)有條件的編譯。

    外部變量

    外部變量在其所屬的整個(gè)源代碼文件中可見,但在其他模塊中不會(huì)自動(dòng)可見。需要使用關(guān)鍵字extern來(lái)聲明。
    主模塊中float interest_rate;輔助模塊extern float interest_rate;

    .o文件

    如果源代碼文件已被編譯為.o文件,則應(yīng)僅當(dāng)修改該文件時(shí)才重新編譯,否則應(yīng)盡量使用.o文件,gcc database.c keyboard.c

    生成工具

    應(yīng)該就是上面的makefile和cmake。可以檢查源代碼和目標(biāo)文件的時(shí)間和日期郵戳,并根據(jù)定義的依存性,指示編譯器只重新編譯那些依賴于被修改的文件的文件。避免了不必要的編譯,最大化效率。

    適合于大型工程。

    預(yù)處理器

    gcc -E進(jìn)行預(yù)處理,根據(jù)源代碼的指令(預(yù)處理器編譯指令)對(duì)源代碼進(jìn)行修改。

    #define

  • 替換宏
    #define text1 text2
    預(yù)編譯器把源代碼文件中所有的text1替換為text2。如果text1位于雙引號(hào)中,則不替換。不會(huì)修改源代碼文件。

  • 函數(shù)宏
    函數(shù)宏的優(yōu)點(diǎn):對(duì)參數(shù)類型不敏感,可以將任何數(shù)值類型的變量傳遞給接受數(shù)值參數(shù)的函數(shù)宏。
    #define HALFOF(value) ((value) / 2)
    #define LARGER(x, y) ((x) > (y) ? (x) : (y))

    宏定義時(shí),宏名后必須緊跟左圓括號(hào),不能有空白。并且替換字符串中每個(gè)參數(shù)都要有圓括號(hào)括起。例如:
    #define SQUARE(x) (x) * (x)而不是#define SQUARE (x) x*x

    替換字符串中,如果宏參數(shù)前面有#字符串化運(yùn)算符,展開宏時(shí),該參數(shù)將被轉(zhuǎn)換成被引號(hào)括起來(lái)的字符串。例如:
    #define OUT(x) printf(#x)
    OUT(Hello);被展開為printf("Hello");
    #運(yùn)算符在轉(zhuǎn)換時(shí)會(huì)考慮特殊字符,需要轉(zhuǎn)義時(shí)加\。
    OUT("HELLO");---->printf("\"HELLO\"");

    ##拼接運(yùn)算符,#define CHOP(x) func ## x,將兩個(gè)字符串拼接,不會(huì)加引號(hào),也不對(duì)轉(zhuǎn)義字符做處理,主要用于修改源代碼。salad = CHOP(3) (q, w);—>func3 (q, w);使用##決定了調(diào)用哪個(gè)函數(shù)。

  • 宏和函數(shù)
    宏速度快,函數(shù)代碼長(zhǎng)度短。

  • 查看宏展開
    gcc -E *.c -o *.i

  • #include

    不可以包含一組,但可以嵌套,被包含的文件可以#include,ANSI最多15層。
    尖括號(hào)括起#incldue <stdio.h>在標(biāo)準(zhǔn)目錄查找。雙引號(hào)括起#include "myfile.h"在源代碼文件中查找。也可以在雙引號(hào)中指定路徑。

    #if、#elif、#else和#endif

    有條件控制編譯,無(wú)需用花括號(hào),似乎用處很大 ,例如:

    #if ENGLAND == 1 # include "england.h" #elif FRANCE == 1 # include "france.h" #elif ITALY == 1 #include "italy.h" #else #include "usa.h" #endif

    還可以幫助調(diào)試:
    #if DEBUG == 1
    debugging code here
    #endif

    defined(),檢查是否被定義。用來(lái)避免包含多次頭文件。

    #if defined(prog_h) /* already included */ #else #define prog_h /* header file information goes here */ #endif

    undef(),撤銷定義。

    預(yù)定義的宏

    __DATE__、__TIME__、__LINE__、__FILE__
    預(yù)處理時(shí),__DATE__、__TIME__為編譯時(shí)的日期和時(shí)間。__LINE__被替換為行號(hào),__FILE__替換為文件名,后兩個(gè)最適合于調(diào)試程序或處理錯(cuò)誤。
    printf(" Program %s: (%d) Error opening file ", __FILE__, __LINE__);

    使用命令行參數(shù)

    main(int argc, char *argv[]) // char **argv也行 {/*...*/ }

    argc表示有多少個(gè)命令行參數(shù),argv的長(zhǎng)度為argc,argv[0]指向包括路徑信息的文件名,argv[1]指向程序名后的第一個(gè)參數(shù)。也可以用其他名,傳統(tǒng)這兩個(gè)。
    e:>program smith "little pony"
    參數(shù)含有空格,則雙引號(hào)括起。

    • 一定要檢驗(yàn)用戶輸入的命令行參數(shù)

    總結(jié)

    • 模塊化編程
    • 預(yù)處理編譯指令,#define #include #if #elif #else #endif #undef
    • 函數(shù)宏
    • 命令行參數(shù)。main(int argc, char **argv[])

    總結(jié)

    以上是生活随笔為你收集整理的21天学通c语言总结(3)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。