幾道C筆試題

Q:printf和scanf的返回值是什麼?數組

複製代碼
int main()  
{  
    int i = 43;  
    int n = printf("%d\n",i);
    printf("%d\n",n);     
    return 0;
} 
複製代碼

A:printf函數返回3。因爲其輸出了'4', '3', '\n' 三個字符。多線程


printf返回的是成功輸出到STDOUT的字符數。假設錯誤發生,返回一個負數。函數


scanf返回的是成功賦值的變量個數,假設錯誤發生,返回EOFpost

Q:既然fgetc是接收輸入的字符,返回值用char或者unsigned char不便可了,爲何用int呢?
A:這個主要是因爲文件結束或者讀寫文件出錯的標誌被規定成EOF。也就是-1致使的。unsigned char根本取不到-1這個值。而假設用char作返回值的話,它沒法分辨0xFF字符和EOF。因爲這兩個數值都被char以爲是-1,因此它也不能做爲返回值。優化

Q:此段程序但願輸出數組中的所有元素。但卻沒有獲得想要的結果,是什麼產生歧義?spa

複製代碼
#include <stdio.h> 
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) 
int array[] = {23,34,12,17,204,99,16}; 
int main() 
{
    int d;
    for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
        printf("%d\n",array[d+1]);
    return 0; 
} 
複製代碼

A:執行上面的程序。結果是什麼都沒有輸出,致使這個結果的緣由是sizeof的返回值是一個unsinged int,爲此在比較int d 和TOTAL_ELEMENTS兩個值都被轉換成了unsigned int來進行比較,這樣就致使-1被轉換成一個很大的值,以致於for循環不知足條件。所以,假設不能理解sizeof操做符返回的是一個unsigned int的話,就會產生相似如上的歧義。.net

Q:如下這段程序的輸出結果是:線程

複製代碼
#include <stdio.h> 
#define f(a,b) a##b 
#define g(a)   #a 
#define h(a) g(a)   
int main() 
{
    printf("%s\n", h(f(1,2)));
    printf("%s\n", g(f(1,2)));
    return 0; 
} 
複製代碼

A:在C語言的宏中,#的功能是將其後面的宏參數進行字符串化操做(Stringfication)。而##被稱爲鏈接符(concatenator)。用來將兩個Token鏈接爲一個Token。
看到這段程序你可能會以爲,這兩個printf輸出的同一個結果,可是答案卻非如此。本題的輸出是12和f(1,2)。爲何會這樣呢?因爲這是宏。宏的解開不象函數運行那樣由裏到外。#將右邊的參數作整體的字符串替換,即使是還有一個宏,也不展開,因此,g(f(1,2))->"f(1,2)"。指針

對於h(f(1,2)),因爲h(a)是非#或##的普通宏。需要先宏展開其參數a,即展開f(1,2)爲12,則h(a) 宏替換爲h(12)。進而宏替換爲g(12), 進而宏替換爲"12"。code

Q:假如咱們的a的地址是:0Xbfe2e100, 而且是32位機,那麼這個程序會輸出什麼?

複製代碼
#include <stdio.h>
int main()
{
    int a[5];
    printf("%x\n", a);
    printf("%x\n", a+1);
    printf("%x\n", &a);
    printf("%x\n", &a+1);
    return 0;
}
複製代碼

A:
第一條printf語句應該沒有問題,就是 bfe2e100。 
第二條printf語句你可能會覺得是bfe2e101。那就錯了。a+1。編譯器會編譯成 a+ 1*sizeof(int),int在32位下是4字節。因此是加4,也就是bfe2e104。
第三條printf語句多是你最頭疼的。咱們怎麼知道a的地址?我不知道嗎?可不就是bfe2e100。那豈不成了a==&a啦?這怎麼可能?本身存本身的?或許很是多人會認爲指針和數組是一回事,那麼你就錯了。假設是 int *a,那麼沒有問題,因爲a是指針。因此 &a 是指針的地址,a 和 &a不同。但是這是數組啊a[],因此&a事實上是被編譯成了 &a[0]。 
第四條printf語句就很是天然了。就是bfe2e104。仍是不正確,因爲是&a是數組,被當作int(*)[5]。因此sizeof(a)是5,也就是5*sizeof(int)。也就是bfe2e114。

Q:例如如下代碼爲何結果始終不正確?

複製代碼
#include <stdio.h>
int main()
{
    int a = 2;
    if(a & 1 == 0)
        printf("a & 1 == 0");
    else
        printf("a & 1 != 0");
    return 0;
}
複製代碼

爲何輸出「a & 1 != 0」?
A:這是因爲==的優先級高於表示位與運算符&.因此a & 1 == 0的實際代碼是a & (1 == 0)。也就是a & 0, 固然結果不是預期了。

(優先級:==和!= 高於 & 高於 ^ 高於 | 高於 && 高於 || )。

優先級從高到低:算術運算符,位移運算符,關係運算符,位操做& ^ |

Q:例如如下代碼輸出什麼?

複製代碼
int main()
{
    int i = 6;
    if( ((++i < 7) && ( i++/6)) || (++i <= 9));
        printf("%d\n",i);
    return 0;
}
複製代碼

A:8。本題主要考的是&&和||的短路求值的問題。所爲短路求值:對於(條件1 && 條件2)。假設「條件1」是false,那「條件2」的表達式會被忽略了。對於(條件1 || 條件2),假設「條件1」爲true,而「條件2」的表達式則被忽略了。

Q:sizeof後面可以跟表達式,如下的代碼,爲何i++無效呢?

複製代碼
#include <stdio.h>
int main()
{
    int i = 1;
    sizeof(i++);
    printf("%d\n", i);
    return 0;
}
複製代碼

執行結果:1
A:正因爲sizeof是編譯期求值的,因此假設它跟着表達式,那麼表達式是不被計算的,僅僅是根本表達式的類型獲得它佔用的空間。

Q:如下的程序試圖使用「位操做」來完畢「乘5」的操做,只是這個程序中有個BUG,你知道是什麼嗎?

複製代碼
#include <stdio.h>
#define PrintInt(expr) printf("%s : %d\n",#expr,(expr))
int FiveTimes(int a)
{
    int t;
    t = a<<2 + a;
    return t;
}
int main()
{
    int a = 1;
    PrintInt(FiveTimes(a));
    return 0;
}
複製代碼

A:本題的問題在於函數FiveTimes中的表達式「t = a<<2 + a;」,對於a<<2這個位操做,優先級要比加法要低,因此這個表達式就成了「t = a << (2+a)」,因而咱們就得不到咱們想要的值。

該程序修正例如如下:「t = (a<<2) + a;」

Q:例如如下代碼關於位運算符的操做爲什麼終於結果和預期不符?

複製代碼
#include <stdio.h>
int main()
{
    unsigned char c = 0xfc;
    unsigned int i = ~c;
    printf("%x\n",i);
    return 0;
}
複製代碼

執行結果:0xffffff03
依照上面的代碼,~c應該獲得的是0x03, 那麼結果應該是0x03, 怎麼會是上面的結果呢?
A:這是因爲位運算是被提高到整形運算的。

上面的變量c是無符號字符型,在進行~位運算時,是首先提高爲整形,即爲0x000000fc, 而後取反獲得0xffffff03, 因此i獲得的數值是這個。同理。假設c是char類型。提高爲整形時爲0xfffffffc。再取反獲得的就是0x03。事實上變量被提高有很是多地方。比方short計算時也會提高爲int再繼續計算。

Q:如下這個程序運行後會有什麼錯誤或者效果:

複製代碼
#define MAX 255
int main()
{
    unsigned char A[MAX];
    unsigned chat i;
    for (i = 0; i <= MAX; i++)
        A[i] = i;
}
複製代碼

A:MAX=255,數組A的下標範圍爲:0..MAX-1,下標越界。當i循環到255時。循環內運行: A[255]=255;這句自己沒有問題,但是返回for(i=0;i<=MAX;i++)語句時。由於unsigned char的取值範圍在[0,255]。i++之後i又爲0了,無限循環下去。
注意:char類型爲一個字節,取值範圍是[-128,127],unsigned char取值範圍[0,255]

Q:有a和b兩個整型變量,不用「if」,「? :」,「switch」或者是其它推斷語句,怎樣獲得大者和小者?
A:大者:((a+b)+abs(a-b))/2
   小者:((a+b)-abs(a-b))/2

Q:請定義一個宏,比較兩個數a、b的大小。不能使用大於、小於、if語句
A:可以推斷兩個數相減後的符號,32位整數相減後的符號位:

#define MAX(a,b)  ((((a)-(b))&(1<<31))?

(b):(a))

Q:定義一個宏,求一個結構體struct中某個變量相對於struct的偏移量

A:#define OFFSET(struct, member)  ((unsigned int)&((struct *)0)->member)

Q:求不小於x的最小的2的K次方的數:

複製代碼
int pow2_ceil(unsigned int x)
{
    x--;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x++;
    return x;
}
複製代碼

靈活的位操做可以有效地提升程序執行的效率: 
1.設置x的bit5爲1,其它位不變:x |= (1<<5);
2.設置x的bit5爲0。其它位不變:x &= ~(1<<5);
3.推斷x的bit5是否爲1。(x & (1<<5)) != 0 ?

1:0;
4.推斷一個數是否是偶數:(num & 1) == 0 ? 1:0;

關於C中volatilekeyword的做用:一個定義爲volatile的變量是說這變量可能會被意想不到地改變,這樣。編譯器就不會去若是這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都當心地又一次讀取這個變量的值,而不是使用保存在寄存器裏的備份。
如下是volatile變量的幾個樣例:
     1). 並行設備的硬件寄存器(如:狀態寄存器)
     2). 一箇中斷服務子程序中會訪問到的非本身主動變量(Non-automatic variables,本身主動變量是auto或register變量)
     3). 多線程應用中被幾個任務共享的變量:volatile keyword告訴編譯器不要持有變量的暫時性拷貝。

請看下面情形:A線程將變量複製入寄存器,而後進入循環,重複檢測寄存器的值是否知足必定條件。它期待B線程改變變量的值。在此種狀況下,當B線程改變了變量的值時。已改變的值對其在寄存器的值沒有影響。因此A線程進入死循環。

幾道C筆試題
相關文章
相關標籤/搜索