1) 什麼是先行編譯,何時需要先行編譯:
總是使用不經常改動的大型代碼體。
程式由多個模組組成,所有模組都使用一組標準的包含檔案和相同的編譯選項。在這種情況下,可以將所有包含檔案先行編譯為一個先行編譯頭。
2) char * const p;
char const * p
const char *p
上述三個有什麼區別?
char * const p; //常量指標,p的值不可以修改
char const * p;//指向常量的指標,指向的常量值不可以改
const char *p; //和char const *p
3) char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
結果是:0 0 1 1
解答:str1,str2,str3,str4是陣列變數,它們有各自的記憶體空間;而str5,str6,str7,str8是指標,它們指向相同的常量地區。
4) 以下代碼中的兩個sizeof用法有問題嗎?
void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
{
for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
if( 'a'<=str[i] && str[i]<='z' )
str[i] -= ('a'-'A' );
}
char str[] = "aBcDe";
cout << "str字元長度為: " << sizeof(str)/sizeof(str[0]) << endl;
UpperCase( str );
cout << str << endl;
答:函數內的sizeof有問題。根據文法,sizeof如用於數組,只能測出靜態數組的大小,無法檢測動態分配的或外部數組大小。函數外的str是一個靜態定義的數組,因此其大小為6,函數內的str實際只是一個指向字串的指標,沒有任何額外的與數組相關的資訊,因此sizeof作用於上只將其當指標看,一個指標為4個位元組,因此返回4。
5) 一個32位的機器,該機器的指標是多少位?
指標是多少位只要看地址匯流排的位元就行了。80386以後的機子都是32的資料匯流排。所以指標的位元就是4個位元組了。
6) main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
輸出:2,5
*(a+1)就是a[1],*(ptr-1)就是a[4],執行結果是2,5
&a+1不是首地址+1,系統會認為加一個a數組的位移,是位移了一個數組的大小(本例是5個int)
int *ptr=(int *)(&a+1);
則ptr實際是&(a[5]),也就是a+5
原因如下:
&a是數組指標,其類型為 int (*)[5];
而指標加1要根據指標類型加上一定的值,不同類型的指標+1之後增加的大小不同。
a是長度為5的int數組指標,所以要加 5*sizeof(int)
所以ptr實際是a[5]
但是prt與(&a+1)類型是不一樣的(這點很重要)
所以prt-1隻會減去sizeof(int*)
a,&a的地址是一樣的,但意思不一樣,a是數組首地址,也就是a[0]的地址,&a是對象(數組)首地址,a+1是數組下一元素的地址,即a[1],&a+1是下一個對象的地址,即a[5].
7) 請問以下代碼有什麼問題:
int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}
沒有為str分配記憶體空間,將會發生異常。問題出在將一個字串複製進一個字元變數指標所指地址。雖然可以正確輸出結果,但因為越界進行內在讀寫而導致程式崩潰。
8)
char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);
有什麼錯?
"AAA"是字串常量。s是指標,指向這個字串常量,所以聲明s的時候就有問題。
cosnt char* s="AAA";
然後又因為是常量,所以對是s[0]的賦值操作是不合法的。
9) 寫一個“標準”宏,這個宏輸入兩個參數並返回較小的一個。
.#define Min(X, Y) ((X)>(Y)?(Y):(X))//結尾沒有;
10) 嵌入式系統中經常要用到無限迴圈,你怎麼用C編寫死迴圈。
while(1){}或者for(;;)
軟體開發網 www.mscto.cn
11) 關鍵字static的作用是什嗎?
定義靜態變數
12) 關鍵字const有什麼含意?
表示常量不可以修改的變數。
13) 關鍵字volatile有什麼含意?並舉出三個不同的例子?
提示編譯器對象的值可能在編譯器未監測到的情況下改變。
14) int (*s[10])(int) 表示的是什嗎?
int (*s[10])(int) 函數指標數組,每個指標指向一個int func(int param)的函數。
15) 有以下運算式:
int a=248; b=4;
int const c=21;
const int *d=&a;
int *const e=&b;
int const *f const =&a;
請問下列運算式哪些會被編譯器禁止?為什嗎?
*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;
*c 這是個什麼東東,禁止
*d 說了是const, 禁止
e = &a 說了是const 禁止
const *f const =&a; 禁止
16) 交換兩個變數的值,不使用第三個變數。即a=3,b=5,交換之後a=5,b=3;
有兩種解法, 一種用算術演算法, 一種用^(異或)
a = a + b;
b = a - b;
a = a - b;
or
a = a^b;// 只能對int,char..
b = a^b;
a = a^b;
or
a ^= b ^= a;
17) c和c++中的struct有什麼不同?
c和c++中struct的主要區別是c中的struct不可以含有成員函數,而c++中的struct可以。c++中struct和class的主要區別在於預設的存取許可權不同,struct預設為public,而class預設為private。
18) #include <stdio.h>
#include <stdlib.h>
void getmemory(char *p)
{
p=(char *) malloc(100);
strcpy(p,"hello world");
}
int main( )
{
char *str=NULL;
getmemory(str);
printf("%s/n",str);
free(str);
return 0;
}
程式崩潰,getmemory中的malloc 不能返回動態記憶體, free()對str操作很危險
19) char szstr[10];
strcpy(szstr,"0123456789");
產生什麼結果?為什嗎?
長度不一樣,會造成非法的OS
20) 列舉幾種進程的同步機制,並比較其優缺點。
原子操作
訊號量機制
自旋鎖
管程,會合,分布式系統
21) 進程之間通訊的途徑
共用儲存系統
訊息傳遞系統
管道:以檔案系統為基礎
22) 進程死結的原因
資源競爭及進程推進順序非法
23) 死結的4個必要條件
互斥、請求保持、不可剝奪、環路
24) 死結的處理
鴕鳥策略、預防策略、避免策略、檢測與解除死結
25) 作業系統中進程調度策略有哪幾種?
FCFS(先來先服務),優先順序,時間片輪轉,多級反饋
26) 類的靜態成員和非靜態成員有何區別?
類的靜態成員每個類只有一個,非靜態成員每個對象一個
27) 純虛函數如何定義?使用時應注意什嗎?
virtual void f()=0;
是介面,子類必須要實現
28) 數組和鏈表的區別
數組:資料順序儲存,固定大小
連表:資料可以隨機儲存,大小可動態改變
29) ISO的七層模型是什嗎?tcp/udp是屬於哪一層?tcp/udp有何優缺點?
應用程式層
展示層
會話層
運輸層
網路層
物理鏈路層
物理層
tcp /udp屬於運輸層
TCP 服務提供了資料流傳輸、可靠性、有效流量控制、全雙工系統操作和多工技術等。
與 TCP 不同, UDP 並不提供對 IP 協議的可靠機制、流量控制以及錯誤恢複功能等。由於 UDP 比較簡單, UDP 頭包含很少的位元組,比 TCP 負載消耗少。
tcp: 提供穩定的傳輸服務,有流量控制,缺點是包頭大,冗餘性不好
udp: 不提供穩定的服務,包頭小,開銷小
30) (void *)ptr 和 (*(void**))ptr的結果是否相同?
其中ptr為同一個指標(void *)ptr 和 (*(void**))ptr值是相同的
32)
int main()
{
int x=3;
printf("%d",x);
return 1;
}
問函數既然不會被其它函數調用,為什麼要返回1?
mian中,c標準認為0表示成功,非0表示錯誤。具體的值是某中具體出錯資訊
33) 要對絕對位址0x100000賦值,我們可以用(unsigned int*)0x100000 = 1234;那麼要是想讓程式跳轉到絕對位址是0x100000去執行,應該怎麼做?
*((void (*)( ))0x100000 ) ( );
首先要將0x100000強制轉換成函數指標,即:
(void (*)())0x100000
然後再調用它:
*((void (*)())0x100000)();
用typedef可以看得更直觀些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
34) 已知一個數組table,用一個宏定義,求出資料的元素個數
#define NTBL
#define NTBL (sizeof(table)/sizeof(table[0]))
35) 線程與進程的區別和聯絡? 線程是否具有相同的堆棧? dll是否有獨立的堆棧?
進程是死的,只是一些資源的集合,真正的程式執行都是線程來完成的,程式啟動的時候作業系統就幫你建立了一個主線程。
每個線程有自己的堆棧。DLL中有沒有獨立的堆棧?
這個問題不好回答,或者說這個問題本身是否有問題。因為DLL中的代碼是被某些線程所執行,只有線程擁有堆棧,如果DLL中的代碼是EXE中的線程所調用,那麼這個時候是不是說這個DLL沒有自己獨立的堆棧?如果DLL中的代碼是由DLL自己建立的線程所執行,那麼是不是說DLL有獨立的堆棧?
以上講的是堆棧,如果對於堆來說,每個DLL有自己的堆,所以如果是從DLL中動態分配的記憶體,最好是從DLL中刪除,如果你從DLL中分配記憶體,然後在EXE中,或者另外一個DLL中刪除,很有可能導致程式崩潰。
36) unsigned short A = 10;
printf("~A = %u\n", ~A);
char c=128;
printf("c=%d\n",c);
輸出多少?並分析過程
第一題,~A =0xfffffff5,int值 為-11,但輸出的是uint。所以輸出4294967285
第二題,c=0x10,輸出的是int,最高位為1,是負數,所以它的值就是0x00的補碼就是128,所以輸出-128。
這兩道題都是在考察二進位向int或uint轉換時的最高位處理。
37) 分析下面的程式:
void GetMemory(char **p,int num)
{
*p=(char *)malloc(num);
}
int main()
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
free(str);
if(str!=NULL)
{
strcpy(str,"world");
}
printf("\n str is %s",str); 軟體開發網 www.mscto.com
getchar();
}
問輸出結果是什嗎?
輸出str is world。
free 只是釋放的str指向的記憶體空間,它本身的值還是存在的.所以free之後,有一個好的習慣就是將str=NULL.
此時str指向空間的記憶體已被回收,如果輸出語句之前還存在分配空間的操作的話,這段儲存空間是可能被重新分配給其他變數的,
儘管這段程式確實是存在大大的問題(上面各位已經說得很清楚了),但是通常會列印出world來。
這是因為,進程中的記憶體管理一般不是由作業系統完成的,而是由庫函數自己完成的。
當你malloc一塊記憶體的時候,管理庫向作業系統申請一塊空間(可能會比你申請的大一些),然後在這塊空間中記錄一些管理資訊(一般是在你申請的記憶體前面一點),並將可用記憶體的地址返回。但是釋放記憶體的時候,管理庫通常都不會將記憶體還給作業系統,因此你是可以繼續訪問這塊地址的。
char a[10],strlen(a)為什麼等於15?啟動並執行結果
38) #include "stdio.h"
#include "string.h"
void main()
{
char aa[10];
printf("%d",strlen(aa));
}
sizeof()和初不初始化,沒有關係;
strlen()和初始化有關。
39) char (*str)[20]; /*str是一個數組指標,即指向數組的指標.*/
char *str[20]; /*str是一個指標數組,其元素為指標型資料.*/
40) long a=0x801010;
a+5=?
0x801010用二進位表示為:“1000 0000 0001 0000 0001 0000”,十進位的值為8392720,再加上5就是8392725羅
41) 給定結構
struct A
{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
};
問sizeof(A) = ?
給定結構
struct A
{
char t:4; 4位
char k:4; 4位
unsigned short i:8; 8位
unsigned long m; // 位移2位元組保證4位元組對齊
}; // 共8位元組
42) 下面的函數實現在一個數上加一個數,有什麼錯誤?請改正。
int add_n ( int n )
{
static int i = 100;
i += n;
return i;
}
當你第二次調用時得不到正確的結果,難道你寫個函數就是為了調用一次?問題就出在 static上?
43) 分析一下
#include<iostream.h>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
typedef struct AA
{
int b1:5;
int b2:2;
}AA;
void main()
{
AA aa;
char cc[100];
strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
memcpy(&aa,cc,sizeof(AA));
cout << aa.b1 <<endl;
cout << aa.b2 <<endl;
}
答案是 -16和1
首先sizeof(AA)的大小為4,b1和b2分別佔5bit和2bit.經過strcpy和memcpy後,aa的4個位元組所存放的值是: 0,1,2,3的ASC碼,即00110000,00110001,00110010,00110011所以,最後一步:顯示的是這4個位元組的前5位,和之後的2位分別為:10000,和01,因為int是有正負之分
所以:答案是-16和1
44) 求函數傳回值,輸入x=9999;
int func ( x )
{
int countx = 0;
while ( x )
{
countx ++;
x = x&(x-1);
}
return countx;
}
結果呢?
知道了這是統計9999的位元值中有多少個1的函數,且有9999=9×1024+512+256+15
9×1024中含有1的個數為2;
512中含有1的個數為1;
256中含有1的個數為1;
15中含有1的個數為4; 軟體開發網 www.mscto.com
故共有1的個數為8,結果為8。
1000 - 1 = 0111,正好是原數取反。這就是原理。
用這種方法來求1的個數是很效率很高的。
不必去一個一個地移位。迴圈次數最少。
int a,b,c 請寫函數實現C=a+b ,不可以改變資料類型,如將c改為long int,關鍵是如何處理溢出問題
bool add (int a, int b,int *c)
{
*c=a+b;
return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b)));
}
45) 分析:
struct bit
{
int a:3;
int b:2;
int c:3;
};
int main()
{
bit s;
char *c=(char*)&s;
cout<<sizeof(bit)<<endl;
*c=0x99;
cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
int a=-1;
printf("%x",a);
return 0;
}
輸出為什麼是
4
1
-1
-4
ffffffff
因為0x99在記憶體中表示為 100 11 001 , a = 001, b = 11, c = 100。當c為有符合數時, c = 100, 最高1為表示c為負數,負數在電腦用補碼錶示,所以c = -4;同理 b = -1;當c為有符合數時, c = 100,即 c = 4,同理 b = 3。
46) 位域 :
有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需占幾個或一個二進位位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為幾個不同的地區, 並說明每個地區的位元。每個域有一個網域名稱,允許在程式中按網域名稱進行操作。 這樣就可以把幾個不同的對象用一個位元組的二進位位域來表示。一、位域的定義和位域變數的說明位域定義與結構定義相仿,其形式為:
struct 位域結構名 { 位域列表 }; 其中位域列表的形式為: 類型說明符 位網域名稱:位域長度
例如:
struct bs
{
int a:8;
int b:2;
int c:6;
};
位域變數的說明與結構變數說明的方式相同。 可採用先定義後說明,同時定義說明或者直接說明這三種方式。例如:
struct bs
{
int a:8;
int b:2;
int c:6;
}data;
說明data為bs變數,共佔兩個位元組。其中位域a佔8位,位域b佔2位,位域c佔6位。對於位域的定義尚有以下幾點說明:
一個位域必須儲存在同一個位元組中,不能跨兩個位元組。如一個位元組所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bs
{
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*從下一單元開始存放*/
unsigned c:4
}
在這個位域定義中,a占第一位元組的4位,後4位填0表示不使用,b從第二位元組開始,佔用4位,c佔用4位。
由於位域不允許跨兩個位元組,因此位域的長度不能大於一個位元組的長度,也就是說不能超過8位二進位。
位域可以無位網域名稱,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
struct k
{
int a:1
int :2 /*該2位不能使用*/
int b:3
int c:2
};
從以上分析可以看出,位域在本質上就是一種結構類型, 不過其成員是按二進位分配的。
位域的使用位域的使用和結構成員的使用相同,其一般形式為: 位域變數名?位網域名稱 位域允許用各種格式輸出。
main()
{
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
}
bit,*pbit;
bit.a=1;
bit.b=7;
bit.c=15;
pri
47) 改錯:
#include <stdio.h>
int main(void)
{
int **p;
int arr[100];
p = &arr;
return 0;
}
解答:搞錯了,是指標類型不同,int **p; //二級指標&arr; //得到的是指向第一維為100的數組的指標
#include <stdio.h>
int main(void)
{
int **p, *q;
int arr[100];
q = arr;
p = &q;
return 0;
}
48) 下面這個程式執行後會有什麼錯誤或者效果:
#define MAX 255
int main()
{
unsigned char A[MAX],i;//i被定義為unsigned char
for (i=0;i<=MAX;i++)
A[i]=i;
return 0;
}
解答:死迴圈加數組越界訪問(C/C++不進行數組越界檢查)MAX=255 數組A的下標範圍為:0..MAX-1,這是其一..
其二.當i迴圈到255時,迴圈內執行:A[255]=255;這句本身沒有問題..但是返回for (i=0;i<=MAX;i++)語句時,由於unsigned char的取值範圍在(0..255),i++以後i又為0了..無限迴圈下去。
49) struct name1
{
char str;
short x;
int num;
}
struct name2
{
char str;
int num;
short x;
}
sizeof(struct name1)=8,sizeof(struct name2)=12
在第二個結構中,為保證num按四個位元組對齊,char後必須留出3位元組的空間;同時為保證整個結構的自然對齊(這裡是4位元組對齊),在x後還要補齊2個位元組,這樣就是12位元組。
50) intel:
A.c 和B.c兩個c檔案中使用了兩個相同名字的static變數,編譯的時候會不會有問題?這兩個static變數會儲存到哪裡(棧還是堆或者其他的)?
static的全域變數,表明這個變數僅在本模組中有意義,不會影響其他模組。他們都放在資料區,但是編譯器對他們的命名是不同的。如果要使變數在其他模組也有意義的話,需要使用extern關鍵字。
51) struct s1
{
int i: 8;
int j: 4;
int a: 3;
double b;
};
struct s2
{
int i: 8;
int j: 4;
double b;
int a:3;
};
printf("sizeof(s1)= %d\n", sizeof(s1));
printf("sizeof(s2)= %d\n", sizeof(s2));
result: 16, 24
第一個struct s1
{
int i: 8;
int j: 4;
int a: 3;
double b;
};
理論上是這樣的,首先是i在相對0的位置,佔8位一個位元組,然後,j就在相對一個位元組的位置,由於一個位置的位元組數是4位的倍數,因此不用對齊,就放在那裡了,然後是a,要在3位的倍數關係的位置上,因此要移一位,在15位的位置上放下,目前總共是18位,折算過來是2位元組2位的樣子,由於double 是8位元組的,因此要在相對0要是8個位元組的位置上放下,因此從18位開始到8個位元組之間的位置被忽略,直接放在8位元組的位置了,因此,總共是16位元組。
第二個最後會對照是不是結構體內最大資料的倍數,不是的話,會補成是最大資料的倍數。