C語言面試題2
1 預處理
問題1:什麼是預編譯?何時需要預編譯?
答:
預編譯又稱預處理,是整個編譯過程最先做的工作,即程式執行前的一些預處理工作。主要處理#開頭的指令。如拷貝#include包含的檔案程式碼、替換#define定義的巨集、條件編譯#if等。.
何時需要預編譯:
1、總是使用不經常改動的大型程式碼體。
2、程式由多個模組組成,所有模組都使用一組標準的包含檔案和相同的編譯選項。在這種情況下,可以將所有包含檔案預編譯為一個預編譯頭。
問題2:寫一個“標準”巨集,這個巨集輸入兩個引數並返回較小的一個
答:#define MIN(x, y) ((x)<(y)?(x):(y)) //
問題3:#與##的作用?
答:#是把巨集引數轉化為字串的運算子,##是把兩個巨集引數連線的運算子。
例如:
#define STR(arg) #arg 則巨集STR(hello)展開時為”hello”
#define NAME(y) name_y 則巨集NAME(1)展開時仍為name_y
#define NAME(y) name_##y
#define DECLARE(name, type) typename##_##type##_type,
則巨集DECLARE(val, int)展開為int val_int_type
問題4:如何避免標頭檔案被重複包含?
答:
例如,為避免標頭檔案my_head.h被重複包含,可在其中使用條件編譯:
#ifndef _MY_HEAD_H
#define _MY_HEAD_H /*空巨集*/
/*其他語句*/
#endif
2 關鍵字
問題1:static關鍵字的作用?
答:
Static
1靜態儲存型別:
在函式內定義的靜態區域性變數,該變數存在記憶體的靜態區,所以即使該函式執行結束,靜態變數的值不會被銷燬,函式下次執行時能仍用到這個值。
在函式外定義的靜態變數——靜態全域性變數,該變數的作用域只能在定義該變數的檔案中,不能被其他檔案通過extern引用。
2 內部連結屬性
靜態函式只能在宣告它的原始檔中使用。
問題2:const關鍵字的作用?
答:
1宣告常變數,使得指定的變數不能被修改。
const int a = 5;/*a的值一直為5,不能被改變*/
const int b; b = 10;/*b的值被賦值為10後,不能被改變*/
const int *ptr; /*ptr為指向整型常量的指標,ptr的值可以修改,但不能修改其所指向的值*/
int *const ptr;/*ptr為指向整型的常量指標,ptr的值不能修改,但可以修改其所指向的值*/
const int *const ptr;/*ptr為指向整型常量的常量指標,ptr及其指向的值都不能修改*/
2修飾函式形參,使得形參在函式內不能被修改,表示輸入引數。
如int fun(const int a);或int fun(const char *str);
3修飾函式返回值,使得函式的返回值不能被修改。
const char *getstr(void);使用:const *str= getstr();
const int getint(void); 使用:const int a =getint();
問題3:volatile關鍵字的作用?
答:
volatile指定的關鍵字可能被系統、硬體、程序/執行緒改變,強制編譯器每次從記憶體中取得該變數的值,而不是從被優化後的暫存器中讀取。例子:硬體時鐘;多執行緒中被多個任務共享的變數等。
問題4:extern關鍵字的作用?
答:
1用於修飾變數或函式,表明該變數或函式都是在別的檔案中定義的,提示編譯器在其他檔案中尋找定義。
extern int a;
extern int *p;
extern int array[];
extern void fun(void);
其中,在函式的宣告帶有關鍵字extern,僅僅是暗示這個函式可能在別的原始檔中定義,沒有其他作用。如:
標頭檔案A:A_MODULE.h中包含
extern int func(int a, int b);
原始檔A: A_MODULE.c中
#include “A_MODULE.h”
int func(int a, int b)
{
returna+b;
}
此時,展開標頭檔案A_MODULE.h後,為
extern int func(int a, int b);/*雖然暗示可能在別的原始檔中定義,但又在本檔案中定義,所以extern並沒有起到什麼作用,但也不會產生錯誤*/
int func(int a, int b)
{
returna+b;
}
而原始檔B:B_MODULE.c中,
#include “A_MODULE.h”
int ret = func(10,5);/
展開標頭檔案A_MODULE.h後,為
extern int func(int a, int b);/*暗示在別的原始檔中定義,所以在下面使用func(5,10)時,在連結的時候到別的目標檔案中尋找定義*/
int ret = func(10,5);
2 用於extern “c
extern “c”的作用就是為了能夠正確實現C++程式碼呼叫其他C語言程式碼。加上extern "C"後,會指示編譯器這部分程式碼按C語言的編譯方式進行編譯,而不是C++的。
C++作為一種與C相容的語言,保留了一部分面向過程語言的特點,如可以定義不屬於任何類的全域性變數和函式,但C++畢竟是一種面向物件的語言,為了支援函式的過載,對函式的編譯方式與C的不同。例如,在C++中,對函式void fun(int,int)編譯後的名稱可能是_fun_int_int,而C中沒有過載機制,一般直接利用函式名來指定編譯後函式的名稱,如上面的函式編譯後的名稱可能是_fun。
這樣問題就來了,如果在C++中呼叫的函式如上例中的fun(1,2)是用C語言在原始檔a_module.c中實現和編譯的,那麼函式fun在目標檔案a_module.obj中的函式名為_fun,而C++在原始檔b_module.cpp通過呼叫其對外提供的標頭檔案a_module.h引用後,呼叫fun,則直接以C++的編譯方式來編譯,使得fun編譯後在目標檔案b_module.obj的名稱為_fun_int_int,這樣在連結的時候,因為_fun_int_int的函式在目標檔案a_module.obj中不存在,導致了連結錯誤。
解決方法是讓b_module.cpp知道函式fun是用C語言實現和編譯了,在呼叫的時候,採用與C語言一樣的方式來編譯。該方法可以通過extern “C”來實現(具體用法見下面)。一般,在用C語言實現函式的時候,要考慮到這個函式可能會被C++程式呼叫,所以在設計標頭檔案時,應該這樣宣告標頭檔案:
/*標頭檔案a_module.h*/
/*標頭檔案被CPP檔案include時,CPP檔案中都含有該自定義的巨集__cplusplus*/
/*這樣通過extern “C”告訴C++編譯器,extern “C”{}裡包含的函式都用C的方式來編譯*/
#ifdef __cplusplus
extern “C”
{
#endif
extern void fun(int a, int b);
#ifdef __cplusplus
}
#endif
extern "C"的使用方式
1. 可以是單一語句
extern "C" doublesqrt(double);
2. 可以是複合語句, 相當於複合語句中的宣告都加了extern "C"
extern "C"
{
double sqrt(double);
int min(int, int);
}
3.可以包含標頭檔案,相當於標頭檔案中的宣告都加了extern"C"
extern "C"
{
#include <cmath>
}
4. 不可以將extern"C" 新增在函式內部
5. 如果函式有多個宣告,可以都加extern"C", 也可以只出現在第一次宣告中,後面的宣告會接受第一個連結指示符的規則。
6. 除extern"C", 還有extern "FORTRAN" 等。
問題5:sizeof關鍵字的作用?
答:
sizeof是在編譯階段處理,且不能被編譯為機器碼。sizeof的結果等於物件或型別所佔的記憶體位元組數。sizeof的返回值型別為size_t。
變數:int a; sizeof(a)為4;
指標:int *p; sizeof(p)為4;
陣列:int b[10]; sizeof(b)為陣列的大小,4*10;int c[0]; sizeof(c)等於0
結構體:struct (int a; char ch;)s1; sizeof(s1)為8 與結構體位元組對齊有關。
注意:不能對結構體中的位域成員使用sizeof
sizeof(void)等於1
sizeof(void *)等於4
3 結構體
問題1:結構體的賦值?
答:
C語言中對結構體變數的賦值或者在初始化或者在定義後按欄位賦值。
方式1:初始化
struct tag
{
chara;
int b;
}x = {‘A’, 1};/*初始化*/
或
struct tag
{
char a;
int b;
};
struct tag x = {‘A’,1};/*在定義變數時初始化*/
GNU C中可使用另外一種方式:
struct tag
{
char a;
int b;
}x =
{
.a = ‘A’,
.b =1;
};
或
struct tag
{
char a;
int b;
};
struct tag x =
{
.a= ‘A’,
.b=1,
};
方式2:定義變數後按欄位賦值
struct tag
{
char a;
int b;
};
struct tag x;/*定義變數*/
x.a = ‘A’;/*按欄位賦值*/
x.b = 1; /*按欄位賦值*/
而當你使用初始化的方式來賦值時,如x = {‘A’,1};則出錯。
方式3:結構變數間的賦值
struct tag
{
chara;
int b;
};
struct tag x,y;
x.a=’A’;
x.b=1;
y = x;/*結構變數間直接賦值*/
問題2:結構體變數如何比較?
答:雖然結構體變數之間可以通過=直接賦值,但不同通過比較符如==來比較,因為比較符只作用於基本資料型別。這個時候,只能通過int memcmp(const void *s1, const void *s2, size_t n);來進行記憶體上的比較。
問題3:結構體位域
答:
位域是一個或多個位的欄位,不同長度的欄位(如宣告為unsigned int型別)儲存於一個或多個其所宣告型別的變數中(如整型變數中)。
位域的型別:可以是char、short、int,多數使用int,使用時最好帶上signed或unsigned
位域的特點:欄位可以不命名,如unsignedint :1;可用來填充;unsigned int :0; 0寬度用來強制在下一個整型(因此處是unsigned int型別)邊界上對齊。
位域的定義:
struct st1
{
unsigned chara:7;/*欄位a佔用了一個位元組的7個bit*/
unsigned charb:2;/*欄位b佔用了2個bit*/
unsigned charc:7;/*欄位c佔用了7個bit*/
}s1;
sizeof(s1)等於3。因為一個位域欄位必須儲存在其位域型別的一個單元所佔空間中,不能橫跨兩個該位域型別的單元。也就是說,當某個位域欄位正處於兩個該位域型別的單元中間時,只使用第二個單元,第一個單元剩餘的bit位置補(pad)0。
於是可知Sizeof(s2)等於3*sizeof(int)即12
struct st2
{
unsigned inta:31;
unsigned intb:2;/*前一個整型變數只剩下1個bit,容不下2個bit,所以只能存放在下一個整型變數*/
unsigned int c:31;
}s2;
位域的好處:
1.有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態,用一位二進位即可。這樣節省儲存空間,而且處理簡便。這樣就可以把幾個不同的物件用一個位元組的二進位制位域來表示。
2.可以很方便的利用位域把一個變數給按位分解。比如只需要4個大小在0到3的隨即數,就可以只rand()一次,然後每個位域取2個二進位制位即可,省時省空間。
位域的缺點:
不同系統對位域的處理可能有不同的結果,如位段成員在記憶體中是從左向右分配的還是從右向左分配的,所以位域的使用不利於程式的可移植性。
問題4:結構體成員陣列大小為0
結構體陣列成員的大小為0是GNU C的一個特性。好處是可以在結構體中分配不定長的大小。如
typedef struct st
{
inta;
int b;
char c[0];
}st_t;
sizeof(st_t)等於8,即char c[0]的大小為0.
相關推薦
C語言面試題2
1 預處理 問題1:什麼是預編譯?何時需要預編譯? 答: 預編譯又稱預處理,是整個編譯過程最先做的工作,即程式執行前的一些預處理工作。主要處理#開頭的指令。如拷貝#include包含的檔案程式碼、替換#define定義的巨集、條件編譯#if等。. 何時需要預編譯: 1、總是使用不經常改動的
經典C語言面試題2:static關鍵字的用法?
C語言中static關鍵字的用法主要有以下三種:1、在函式體內,static變數的作用範圍為該函式體,該變數的記憶體只能被分配一次,下次呼叫時維持上次的值(即具有記憶功能)。2、在模組內的static全域性變數可以被模組內的所有函式訪問,但是不能被模組外的函式訪問(注:即使在
C語言面試題分類->排序算法
OS sort 試題 時間復雜度 ups popup popu 使用 body 1.選擇排序。 每次將最小的數,與剩余數做比較。找到更小的,做交換。 時間復雜度:O(n2) 空間復雜度:O(1) 優缺點:耗時但內存空間使用小。 void selectSor
C語言面試題分類->回調
指向 name 傳輸 join 接口 但是 PE AS 一個數 本文主要講解如果實現回調,特別是在封裝接口的時候,回調顯得特別重要,我們首先假設有兩個程序員在寫代碼,A程序員寫底層驅動接口,B程序員寫上層應用程序,然而此時底層驅動接口A有一個數據d需要傳輸給B,此時有兩種方
智郵普創c語言面試題 ---- 字母概率
arr apple void != stdio.h app words 遊戲 包含 題目描述 小明最近對概率問題很感興趣。一天,小明和小紅一起玩一個概率遊戲,首先小明給出一個字母和一個單詞,然後由小紅計算這個字母在這個單詞中出現的概率。字母不區分大小寫。 例如,給定的字母是
C語言面試題---指標篇(三)
版本宣告:本文轉載於公眾號TeachPlus C語言面試題---指標篇(三) 了解了記憶體空間,接下來我們就一起看一下指標自身用法的一些題目,先來看這樣一道題目: 分析下面程式碼:` # include <stdio.h> # include
C語言面試題---指標篇(一)
版本宣告:本文轉載於公眾號TeachPlus 指標的使用,一直是c語言面試題中必考的部分, 因為指標本身使用的複雜性與普適性,所以考點非常多,而且也可以與其他知識相互結合, 因此我們將會使用五篇專題的篇幅來介紹指標。分析下面的程式,指出程式中的錯誤:
C語言面試題---指標篇(二)
# include <stdio.h># include <stdlib.h># include <string.h>void getMemory( char **p , int num){ *p = malloc(num);} int main() {
100道c語言面試題
題目來源: 1、中興、華為、慧通、英華達、微軟亞洲技術中心等中 外企業面試題目; 2、C 語言面試寶典(林銳《高質量程式設計第三版》)。 說明: 1、部分C 語言面試題中可能會參雜部分和C++ 相關的知 識,為了保持題目的靈活性故保留,但選題最終還是 會以C
C語言面試題大彙總 (影象處理方向)
1、區域性變數能否和全域性變數重名? 答:能,區域性會遮蔽全域性。要用全域性變數,需要使用"::" ;區域性變數可以與全域性變數同名,在函式內引用這個變數時,會用到同名的區域性變數,而不會用到全域性變數。對於有些編譯器而言,在同一個函式內可以定義多個同名的區域性變數,比如在兩個迴圈體內都定義一個同名的
C語言面試題
關於“一年有多少秒”的巨集定義 網上關於這個問題的答案都是(365*24*60*60)UL,是錯誤的。 正解:數字和型別是一個整體,()是外人。 #include <stdio.h> #define SECONDS_PER_YEAR (3
9道常見C語言面試題
1、區域性變數能否和全域性變數重名? 答:能,區域性會遮蔽全域性。要用全域性變數,需要使用"::" ;區域性變數可以與全域性變數同名,在函式內引用這個變數時,會用到同名的區域性變數,而不會用到全域性變數。對於有些編譯器而言,在同一個函式內可以定義多個同
12個有趣的C語言面試題(中英文對照)
In this article, we will discuss some interesting problems on C language that can help students to brush up their C programming skills
C語言面試題 4 (查詢整數陣列中第二大的數)
題目:寫一個函式找出一個整數陣列中,第二大的數。【Mirosoft】 PS:1、” 66,66,66,66,66 ”,則沒有第二大數。 2、” 99,99,88,86,68,66 ”,則最大數是88。 下面我先給出查詢最大數字的程式: int GetFirstMaxNumbe
c語言面試題1
> 前處理器(Preprocessor) 1. 用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在這想看到幾件事情: 1).
2016 C語言面試題——字串函式的實現
2016 C語言面試題——字串函式 前言:最近準備找工作了,所以需要做一些準備。先從基本的字串函式的實現開始。如果有發現什麼問題或有什麼疑惑,請及時評論。 strcat /************
C語言面試題---指標篇(四)
解析:首先看最後一個問題, c 是第一個元素的地址, *c 是第一行元素的首地址,其實第一行元素的地址就是第一個元素的地址, **c 是提取第一個元素。為什麼 c , *c 的值相等?c是陣列名,是一個二維指標,它的值就是陣列的首地址,也即第一行元素的首地址(等於 *c ),也等於第一行第一個元素
經典C語言面試題4:位元組對齊的作用
一、什麼是位元組對齊? 在現代計算機中,記憶體空間都是按照字節(byte)劃分的。從理論上講對任何型別的變數的訪問可以從任何地址開始,但實際情況是,訪問特定型別的變數的時候經常在特定的記憶體地址訪問,這就需要各種型別的資料按照一定規則在空間上排列,而不是順序地一
嵌入式開發—C語言面試題
前處理器(Preprocessor) 1. 用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在這想看到幾件事情: 1). #define 語
C語言面試題——位域及大小端模式的理解
這裡涉及大小端的問題,我記為 “小高高,小弟弟(低低)”,就是: “小端模式,是指資料的高位儲存在記憶體的高地址中,資料的低位儲存在記憶體的低地址中” 這是記小端模式的,有點黃,不過好記!那麼大端模式就和這個相反嘍!!~~ 接下來就看一道面試題: #include<