《C語言程序設計》第8章 編譯預處理和動態存儲分配 寫字字帖_第1頁
《C語言程序設計》第8章 編譯預處理和動態存儲分配 寫字字帖_第2頁
《C語言程序設計》第8章 編譯預處理和動態存儲分配 寫字字帖_第3頁
《C語言程序設計》第8章 編譯預處理和動態存儲分配 寫字字帖_第4頁
《C語言程序設計》第8章 編譯預處理和動態存儲分配 寫字字帖_第5頁
已閱讀5頁,還剩15頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第8章編譯預處理和動態存儲分配8.1編譯預處理8.2宏定義8.3文件包含處理8.4動態存儲分配8.1編譯預處理C語言允許在源程序中加入一些“預處理命令”(preprocessingdirective),以改進程序設計環境,提高編程效率。這些預處理指令是由C標準建議的,但是它不是C語言本身的組成部分,不能用C編譯系統直接對它們進行編譯(因為編譯程序不能識別它們)。所謂“編譯預處理”就是在C編譯程序對C源程序進行編譯前,由編譯預處理程序對這些編譯預處理命令行進行處理的過程。在預處理階段,預處理器把程序中的注釋全部刪除;對預處理指令進行處理,如把#include指令指定的頭文件(如stdio.h)的內容復制到#include指令處;對#define指令,進行指定的字符替換(如將程序中的符號常量用指定的字符串代替),同時刪去預處理指令。8.1編譯預處理經過預處理后的程序不再包括預處理指令了,最后再由編譯程序對預處理后的源程序進行實際的編譯處理,得到可供執行的目標代碼。C語言與其他高級語言的一個重要區別是可以使用預處理指令和具有預處理的功能。C語言提供的預處理功能常用的主要有以下3種:1、宏定義;2、文件包含;3、條件編譯。這些預處理命令組成的預處理命令行必須在一行的開頭以”#”號開始,每行的末尾不得用“;”號結束,以區別于C語句、定義和說明語句。這些命令行的語法與C語言中其他部分的語法無關。根據需要,命令行可以出現在程序的任何一行的開始部位,其作用一直持續到源文件的末尾。8.2宏定義8.2.1不帶參數的宏定義8.2.2帶參數的宏定義8.2.3終止宏定義8.2.1不帶參數的宏定義1不帶參數的宏定義命令行形式格式:#define宏名替換文本或者:#define宏名在define、宏名和宏替換文本之間用空格隔開。例如:#define SIZE 100以上標識符SIZE稱為“宏名”,是用戶定義的標識符,因此,不得與程序中的其他名字相同。在編譯時,在此命令行之后,預處理程序對源程序中的所有名為SIZE的標識符用100三個字符來替換,這個替換過程稱為“宏替換”。但要注意:不能認為“SIZE等于整數100”。#define命令行可以不包含“替換文本”,這種情況下僅說明標識符“被定義”。8.2.1不帶參數的宏定義2替換文本中可以包含已定義過的宏名例8.1計算圓面積。#include<stdio.h>#definePI3.1415926#defineR3.0#defineSPI*R*R /*S的宏定義使用了前面的PI和R宏定義*/intmain(){

printf(“圓的面積=%f”,S); return0;}運行結果:圓的面積=28.274333分析:該例中既有宏定義,又有宏定義的多重替換,這樣求圓的面積,只需將宏名S進行展開后計算,輸出即可。8.2.1不帶參數的宏定義3當宏定義在一行中寫不下,需要在下一行繼續時,只需在最后一個字符后緊接著加一個反斜線“\”。例如:#define LEAP_YEAR year%4==0\&&year%100!=0||year%400==0第一列如果在“\”前或在下一行的開頭留有許多空格,則在宏替換時也將加入這些空格。4同一個宏名不能重復定義,除非兩個宏定義命令行完全一致。5替換文本不能替換雙引號中與宏名相同的字符串。例8.2宏名相同的字符串不能替換。#define BOOK “TheRedandTheBlack”intmain(){

printf(“%s\n”,”BOOK”); return0;}運行結果:BOOK8.2.1不帶參數的宏定義6替換文本并不替換用戶標識符中的成分。例如,宏名YES,不會替換標識符YESORNO中的YES。7用作宏名的標識符通常用大寫字母表示,這并不是語法規定,只是一種習慣,以便與程序中的其他標識符相區別。8在C程序中,宏定義的定義位置一般寫在程序的開頭。返回8.2.2帶參數的宏定義1帶參數的宏定義命令行形式如下:格式:#define 宏名(形參表) 替換文本如果定義帶參數的宏,在對源程序進行預處理時,將程序中出現宏名的地方均用替換文本替換,并用實參代替替換文本中的形參。例8.3編寫程序,使用帶參數的宏定義。#include<stdio.h>#defineMAX(a,b) a>b?a:b /*定義帶參數的宏MAX*/#defineSQR(c)c*c /*定義帶參數的宏SQR*/intmain(){

intx=3,y=4; x=MAX(x,y);

y=SQR(x);

printf(“x=%d,y=%d\n”,x,y);

return0;}運行結果:x=4,y=16對于帶參的宏定義有以下問題需要說明:2.帶參宏定義中,宏名和形參表之間不能有空格出現。例如把:

#defineMAX(a,b)(a>b)?a:b寫為:

#defineMAX(a,b)(a>b)?a:b將被認為是無參宏定義,宏名MAX代表字符串(a,b)(a>b)?a:b。宏展開時,宏調用語句:

max=MAX(x,y);將變為:

max=(a,b)(a>b)?a:b(x,y);這顯然是錯誤的。8.2.2帶參數的宏定義3.在帶參宏定義中,形式參數不分配內存單元,因此不必作類型定義。而宏調用中的實參有具體的值。要用它們去代換形參,因此必須作類型說明。這是與函數中的情況不同的。在函數中,形參和實參是兩個不同的量,各有自己的作用域,調用時要把實參值賦予形參,進行“值傳遞”。而在帶參宏中,只是符號代換,不存在值傳遞的問題。4.在宏定義中的形參是標識符,而宏調用中的實參可以是表達式。例8.4宏調用實參為表達式。#defineSQ(y)(y)*(y)main(){

int

a,sq;

printf("inputanumber:");

scanf("%d",&a);sq=SQ(a+1);printf("sq=%d\n",sq);}運行結果:inputanumber:3sq=16分析:上例中第一行為宏定義,形參為y。程序第七行宏調用中實參為a+1,是一個表達式,在宏展開時,用a+1代換y,再用(y)*(y)代換SQ,得到如下語句:

sq=(a+1)*(a+1);這與函數的調用是不同的,函數調用時要把實參表達式的值求出來再賦予形參。而宏代換中對實參表達式不作計算直接地照原樣代換。8.2.2帶參數的宏定義5.在宏定義中,字符串內的形參通常要用括號括起來以避免出錯。在上例中的宏定義中(y)*(y)表達式的y都用括號括起來,因此結果是正確的。如果去掉括號,把程序改為以下形式:例8.5#defineSQ(y)y*ymain(){

int

a,sq;

printf("inputanumber:");

scanf("%d",&a);sq=SQ(a+1);printf("sq=%d\n",sq);}運行結果:inputanumber:3sq=7分析:同樣輸入3,但結果卻是不一樣的。問題在哪里呢?這是由于代換只作符號代換而不作其它處理而造成的。宏代換后將得到以下語句:

sq=a+1*a+1;由于a為3故sq的值為7。這顯然與題意相違,因此參數兩邊的括號是不能少的。即使在參數兩邊加括號還是不夠的,請看下面程序:8.2.2帶參數的宏定義例8.6#defineSQ(y)(y)*(y)main(){

int

a,sq;

printf("inputanumber:");

scanf("%d",&a);sq=160/SQ(a+1);printf("sq=%d\n",sq);}運行結果:inputanumber:3sq=160分析:本程序與前例相比,只把宏調用語句改為:

sq=160/SQ(a+1);運行本程序如輸入值仍為3時,希望結果為10。為什么會得這樣的結果呢?分析宏調用語句,在宏代換之后變為:

sq=160/(a+1)*(a+1);a為3時,由于“/”和“*”運算符優先級和結合性相同,則先作160/(3+1)得40,再作40*(3+1)最后得160。為了得到正確答案應在宏定義中的整個字符串外加括號,程序修改如例8.78.2.2帶參數的宏定義6帶參的宏和帶參函數很相似,但有本質上的不同,除上面已談到的各點外,把同一表達式用函數處理與用宏處理兩者的結果有可能是不同的。例8.8main(){

inti=1;

while(i<=5)

printf("%d\n",SQ(i++));}SQ(inty){return((y)*(y));}例8.9#defineSQ(y)((y)*(y))main(){

inti=1;

while(i<=5)

printf("%d\n",SQ(i++));}例8.8運行結果:1491625例8.9運行結果:19258.2.2帶參數的宏定義7宏定義也可用來定義多個語句,在宏調用時,把這些語句又代換到源程序內??聪旅娴睦印@?.10#defineSSSV(s1,s2,s3,v)s1=l*w;s2=l*h;s3=w*h;v=w*l*h;main(){

intl=3,w=4,h=5,sa,sb,sc,vv;

SSSV(sa,sb,sc,vv);

printf("sa=%d\nsb=%d\nsc=%d\nvv=%d\n",sa,sb,sc,vv);}運行結果:sa=12sb=15sc=20vv=60分析:程序第一行為宏定義,用宏名SSSV表示4個賦值語句,4個形參分別為4個賦值符左部的變量。在宏調用時,把4個語句展開并用實參代替形參。使計算結果送入實參之中。返回8.2.3終止宏定義可以用#undef提前終止宏定義的作用域。例如:#definePI3.14main()#undefPI以上PI的作用域從#definePI3.14命令行開始,到#undefPI命令行結束。從#undef以后PI變成無定義,不再代表3.14了。8.3文件包含處理所謂文件包含,是指在一個文件中,去包含另一個文件的全部內容。C語言用#include命令行來實現文件包含的功能。格式:#include “文件名”或 #include <文件名>在預編譯時,預編譯程序將用指定文件中的內容來替換此命令行。如果文件名用雙引號括起來,系統先在源程序所在的目錄內查找指定的包含文件,如果找不到,再按照系統指定的標準方式到有關目錄中去尋找;如果文件名用尖括號括起來,系統將直接按照系統指定的標準方式到有關目錄中尋找。說明:1包含文件的#include命令行通常應書寫在所用源程序文件的開頭,故有時也把包含文件稱作“頭文件“。頭文件名可以由用戶指定,其后綴不一定用”.h”。2包含文件中,一般包含有一些公用的#define命令行、外部說明或對(庫)函數的原型說明。例如stdio.h就是這樣的頭文件。3當包含文件修改后,對包含該文件的源程序必須重新進行編譯連接。4在一個程序中,允許有任意多個#include命令行。5在包含文件中還可以包含其他文件。8.4動態存儲分配8.4.1malloc函數和free函數8.4.2calloc函數8.4.1malloc函數和free函數1malloc函數格式:(類型說明符*)malloc(size)功能:在內存的動態存儲區中分配一塊長度為"size"字節的連續區域。函數的返回值為該區域的首地址?!邦愋驼f明符”表示把該區域用于何種數據類型。(類型說明符*)表示把返回值強制轉換為該類型指針。“size”是一個無符號數。假設shortint型數據占2個字節,float型數據占4字節存儲單元,則以下程序段將使pi指向一個shortint類型的存儲單元,使pf指向一個float類型的存儲單元:shortint*pi;float*pf;pi=(short*)malloc(2);pf=(float*)malloc(4);由于在ANSIC中malloc函數返回的指針為void*(無值型),故在調用函數時,必須利用強制類型轉換將其轉成所需的類型。上面的程序段中,調用malloc函數時括號中的*號不可少,否則就轉換成普通變量類型而不是指針類型了。在動態申請存儲空間時,若不能確定數據類型所占字節數,可以使用sizeof運算符來求得。例如:

pi=(int*)malloc(sizeof(int)); pf=(float*)malloc(sizeof(float));這是一種常用的形式。此時將由系統來計算指定類型的字節數,采用這種形式將有利于程序的移植。8.4.1malloc函數和free函數2free函數格式:free(void*ptr);功能:釋放ptr所指向的一塊內存空間,ptr是一個任意類型的指針變量,它指向被釋放區域的首地址。被釋放區應是由malloc或calloc函數所分配的區域。例8.11分配一塊區域,輸入一個學生數據。main(){

struct

stu{

intnum;char*name;charsex;floatscore;}*ps;

ps=(struct

stu*)malloc(sizeof(struct

stu));

ps->num=102;

ps->name="Zhangping";

ps->sex='M';

ps->score=62.5;

printf("Number=%d\nName=%s\n",ps->num,ps->name);

printf("Sex=%c\nScore=%f\n",ps->sex,ps->score);

free(ps);}運行結

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論