《C語言程式設計進階》-翁愷-期末試卷30題及解析

NO IMAGE

1、指標,字元陣列

若定義

  1. char s[2][3]={“ab”, “cd”}, *p=(char *)s;

那麼下列表示式語法正確,並且其值與 s[1][1]相等的表示式(並非一定與其等價)是

A. *(s 3)

B. p[1][1]

C. *(p 3)

D. * P 2

答案:D

分析:這道題很好。首先字元型指標p存放的是字串s的首地址,而字串s表示的是這樣一個字串:

ab_

cd_

為了便於理解,“_”表示空格,即沒有元素。題中s[1][1]是d,所以要在ABCD中尋找表示s[1][1]的數。

先來看*(s 3),s表示陣列首地址,不是指標型變數,所以s 3沒有意義。p[1][1]同樣由於p是指標,不存在這種表達。*(p 3)是是p表示的指標後移3位,因此*(p 3)是c。D選項有點複雜,* p 2 這個比較有趣,p是一個char*指標,指向字元陣列首地址,&s[0][0]。首先 的優先順序更高執行 p得到的是&s[0][1],然後*運算子解引用,得到s[0][1],s[0][1]的字元是’b’,然後’b’ 2,得到的就是’d’的ASCII碼. 

下面是一道類似的題目:

若定義 char a[3][3]={“ad”, “ce” , “fb”}, *s = (char *)a; 那麼下列表示式語法正確,並且其值與 a[2][1]相等的表示式是_______。

  A.*(a 3) B.*(*a 5) C.s[2][1] D.* s-2

答案是D,分析可參照:https://blog.csdn.net/zhanshen112/article/details/80786576

2、交換地址、指標
3、陣列名無法
4、靜態本地變數、區域性和全域性變數

靜態本地變數只是無法被修改的區域性變數,定義在函式內部。

5、指標
6、函式返回值 整形型別指標
7、include 標頭檔案
8、結構體
9、指標,*s 的運算順序
10、檔案的讀寫
11、檔案
12、連結串列
13、函式的定義和引數
14、巨集定義函式 巨集定義的運算順序
15、指標 *p 的運算順序
16、函式宣告和呼叫

給定函式原型如下:

  1. int* f(int *p);

而變數定義如下:

A. f(&(i 6));

B. int* p=f(&i);

C.*f(&i)=6;

D. f(&i);

答案:A

分析:

A是先取函式f返回的記憶體單元(引數是&i即i的地址)中儲存的值,並作更改(改為6)
B項 i 6 是算術表示式,不能直接取地址,必須使用變數儲存才能取地址。若改成j=i 6;f(&j);應該就是對的了。
C項 是定義一個指向整型的指標p,並賦值為函式f的返回值(該函式返回一個指標,也就是記憶體地址)
D項 直接以&i為引數執行函式f,返回值不起任何作用

17、結構體 指標
18、指標的指標 

有函式原型為

  1. void f(int, int *);

,主函式中有變數定義:

  1. int a=2, *p=&a;

則下列函式呼叫正確的是

  • A. f(a,&p);
  • B. f(*p, p);
  • C. f(p,a);
  • D. f(*p, a);
  • 答案:B
  • 分析:注意p為指向整型的指標,*p則指向記憶體地址處所存放的資料。*p實際上就是a.

19、typedef 函式指標

  • 用typedef來定義一個函式指標型別PunPtr,它表示的是指向形如void func(int x)的函式,以下正確的表達是: 
  • A. typedef void FunPtr(int x);
  • B. typedef FunPtr fun(int x);
  • C. typedef void (*FunPtr)();
  • D. typedef void (*FunPtr)(int);
  • 答案:D

  • 20、圖形庫函式

21、!!

表示式

  1. !!”2010-01-27”

的值為(以1表示真,0表示假)

答案:1

分析:!!表示“非的非”,即還是原來的布林型別。

22、巨集定義

下列程式段的輸出是_______。

#define DF(a,b)  (a 2*b) 
int s=5;
int k= DF(s 1,s-3);
printf("%d",k);

答案:13

分析:k=DF(5 1,5-3)=5 1 2*5-3=13。注意巨集定義中引數的傳遞,k=DF(5 1,5-3)=(5 1) 2*(5-3)=10是錯誤的。

23、全域性變數、區域性變數、靜態變數的生存期

以下程式碼的輸出是:

int x, y, z, w;
void p(int *y, int x)
{
static int w;
*y  ; x  ; w = x *--y;
printf("%d#%d#%d#%d#",x,*y,z,w);
}
int main(void)
{
int x, y, z, w;
x=y=z=w=1;
do{
static int x;
p(&x, y);
printf("%d#%d#%d#%d#",x,y,z,w);
} while(0);
return 0;
}

答案:2#0#0#2#0#1#1#1#

解析:主要考察區域性變數和全域性變數的生存期,以及靜態本地變數。註釋後的程式碼如下:

int x, y, z, w;    //這裡是全域性變數,定義在任何函式的外面,若不初始化賦值,則均為0;。注意,主函式裡面的變數仍為區域性變數
void p(int *y, int x)    //p函式接收整型指標變數和整型變數的輸入,返回值為空
{
static int w;    //定義靜態變數w,若不初始化賦值,則w==0;
*y  ; x  ; w = x *--y;
printf("%d#%d#%d#%d#",x,*y,z,w);
}
int main(void)
{
int x, y, z, w;
x=y=z=w=1;
do{
static int x;
p(&x, y);
printf("%d#%d#%d#%d#",x,y,z,w);
} while(0);
return 0;
}

從主函式進行分析,主函式內部定義了四個int型變數,若不進行初始化,則全為0。主函式內部定義完之後就進行了初始化,均初始化為1,所以在do-while內部,可以看到由於只定義了靜態區域性變數x,而且沒有初始化賦值,則靜態區域性變數x為0,y,z,w均仍為1。所以

 printf("%d#%d#%d#%d#",x,y,z,w);

的輸出是0#1#1#1#。

再來分析p這個函式:

void p(int *y, int x)    //p函式接收整型指標變數和整型變數的輸入,返回值為空
{
static int w;    //定義靜態變數w,若不初始化賦值,則w==0;
*y  ; x  ; w = x *--y;
printf("%d#%d#%d#%d#",x,*y,z,w);
}

首先p函式無返回值,接受兩個輸入:int型指標變數、int型變數。p函式內部同樣定義了一個靜態區域性變數w,但是w後面有賦值的語句

w = x *--y;

*y 和x 是兩個關鍵,首先*和 ,–運算子處於同一優先順序,結合方向是自右向左。因此*y 可以看做是*(y ),但是由於y 是先執行y,跳出去與*結合,再讓y 。所以*y 實際上等效於先執行*y操作,再執行y 。由於y是指標,因此y 是指標所指記憶體地址的向後移動,移動的大小是一個sizeof(int)。x 同理先執行x(由於沒有任何操作,x不變),再讓x 1,這裡實際上由於x沒有任何操作,x 相當於只執行了x 1,由於區域性變數傳入p函式的x為1,這裡x就等於2了。

由於y是指標變數,因此*y表示取出指標所指記憶體地址的值。由於傳進去的

 static int x;
p(&x, y);

x是靜態變數,則x=0,因此*y=0。這裡要注意p的原型是void p(int *y, int x)  ,而使用p函式時,傳進去的是

  p(&x, y);

順序不要搞反了。w=x *–y,這裡等價於w=x *(–y),由於在上面的*y ,y已經執行了y 1,這裡(–y)先執行–,再執行y,即先執行y-1,再把y-1的結果傳出去。注意這裡的-1指的是減去一個int型變數的記憶體大小。因此y還是原來的記憶體位置。所以*y還是取出原來指標指向記憶體地址的值,即還是原來的靜態區域性變數x,值為0。因此w=x *–y中x=2,(*–y)等於0,所以w=2。由於p函式裡的z只能那個接受全域性變數,因此z=0,所以p函式執行之後列印:2#0#0#2。

24、sizeof和陣列

假設sizeof(int)的值為4,對陣列定義:

  1. int a[3][6];

則sizeof(a[0])的值為____.

答案:24

解析:a[0]裡面有a[0][0],a[0][1]……a[0][5],共6個元素,均為int,因此4*6=24.

25、條件表示式以及&&,||,!

寫出表示“當 x 的取值在 [-10, 0]  的範圍內,結果為真,否則為假”的C語言表示式,注意不要任何空格

答案:x>=-10&&x<=0 或 x<=0&&x>=-10 或 !(x<-10||x>0)

解析:我的答案是(x>=-10)&&(x<=0)?1:0,不如參考答案。

26、&&,||,!

若 int a = 6, b = 0, c = 3,則表示式 a && b || b – c的結果是(以1表示真,0表示假)

答案:1

27、指標、字串和陣列

以下程式碼段的輸出是:

char a[20]="cehiknqtw";
char *s="fbla",*p;
int i, j;
for(p=s; *p; p  ) {
j=0;
while (*p>=a[j] && a[j]!='\0') j  ;
for(i=strlen(a); i>=j; i--) a[i 1] = a[i];
a[j]=*p;
}
printf("%s", a);

答案:abcefhiklnqtw

分析:這段程式碼具有一定的難度。首先a[20]是一個字元陣列,s,p是字元型指標。s剛開始是“fbla”的首地址,因此*s實際上是指向f的記憶體地址的值,即s存放的是f的地址。

核心部分是for迴圈中的語句,

p=s; *p; p  

是將s的指標賦給p,然後逐漸後移,也就是把s字串中的字元指標逐漸都進行賦值。即,p會逐漸等於f,b,l,a的地址。

 while (*p>=a[j] && a[j]!='\0') j  ;

這個語句的意義是在a[]中尋求大於*p所指的字元,當*p==f時,a[]中的h是大於f的,此時j==2,程式跳出while迴圈,進入內層for迴圈,內層for迴圈的意義是把j==2之後的字元都進行後移一位,為*p==f騰出位置,然後將a[2]=*p,也就是把s中的第一個字元填入a[]中。下面依次填入s中其他的字元,因此這個程式完成的任務實際上是把s中的字元按照字元間ASCII數值的大小關係填入a[]中。

28、巨集定義

根據下面的定義,F0(3 4)的輸出結果是_______(注意沒有空格)

#define  F1(var)  printf("var=%d", var)
#define  F0(var)  F1(var * var)

答案:var=19

29、指標的指標

程式T1的程式碼如下,則執行T1  abc  bcd  cde  aed的輸出結果是_______.

int main(int argc, char** argv)
{
while(**argv  !='a');
printf("%s", *argv);
return 0;
}

答案:bcd

分析:

解釋一:程式進來後,argv的內容是 T1 abc bcd cde aed

while(); 注意while迴圈後面有分號,說明printf是在迴圈之後才執行的。

**argv 相當於

  1. return argv;

  2. return **argv

  3. argv (每執行一次,將會指向下一個字串)

當執行第二次迴圈時, abc,此時**argv為’a’,迴圈結束。在此之後,argv 指向了下一個字串,也就是bcd。

解釋二:

1、int main(int argc, char** argv)表示當執行程式時可以帶上引數,所以題目中執行時就寫為T1  abc  bcd  cde  aed,可理解為要執行一個名為T1的程式,並需要對abc  bcd  cde  aed這幾個字串進行處理

2、argc表示引數的個數,此處argc=5,即T1  abc  bcd  cde  aed這5個

3、argv表示的是命令列引數,char** argv可以看成char* argv[],即一個字串陣列,每個元素對應一個字串,值為字串的首地址。因此**argv就是字串的首字母

4、**argv !=’a’就表示當字串的首字母不等於a時,則跳過該字串,繼續判定下個字串。一旦發現某個字串首字母為a,則在argv 作用下輸出下一個字串。比如檢測第一個字串abc時發現首字母為a,則跳出while迴圈,並在argv 作用下輸出bcd

5、**argv 優先順序可以看成**(argv )

以下是一些測試(我的檔名是Cpp1.exe,不影響),就可以看出規律了

補充:**的用法

*表示指標,**表示指標的指標。

例如:int *a;這個語句宣告瞭一個變數a,a的資料型別是int *,也就是整型變數的指標型別(如果不懂什麼是指標,那這個問題就沒有意義了)。也就是說 a的值是一個記憶體地址,在這個地址所在的記憶體空間中存放的是一個整型變數。再看:int **b;這個語句也宣告瞭一個變數b,b的資料型別是int **,也就是整型變數的指標的指標型別(二級指標)。也就是說 b的值是一個記憶體地址,該地址所在的記憶體空間中存放的是一個整型變數的指標(一級指標,或許就是上面那個a的值)。

30、變數的指標

以下程式碼的輸出是 :

void swap( int *pa, int *pb ) 
{
int pt;
pt = *pa, *pa = *pb, *pb = *pa;
}
int main(void)
{    
int x=1, y=2;
swap(&x, &y);
printf("%d%d", x, y);
}

答案:22

分析:看清楚swap函式,不是交換兩個變數的地址,而是把pb的地址又賦給pa,即pa,pb均指向pb的地址。