嵌入式軟件工程師筆試面試必備(很有幫助)

數組指針與指針數組:

數組指針定義 int (*p)[n];

()優先級高,首先說明p是一個指針,指向一個整型的一維數組,這個一維數組的長度是n,也可以說是p的步長。也就是說執行p+1時,p要跨過n個整型數據的長度。(從而指向下一個一維數組)

指針數組定義 int *p[n];

[]優先級高,先與p結合成爲一個數組,再由int*說明這是一個整型指針數組,它有n個指針類型的數組元素。這裏執行p+1時,則p指向下一個數組元素,,而且它們分別是指針變量可以用來存放變量地址。可以這樣賦值 *p=a; 這裏*p表示指針數組第一個元素的值,a的首地址的值。

用變量a給出下面的定義:

a)     一個整型數(An integer)int a;

b) 一個指向整型數的指針(Apointer to an integer) int *a;  

c) 一個指向指針的指針,它指向的指針是指向一個整型數(A pointer to a pointer to an integer)int **a;

d) 一個有10個整型數的數組(An array of 10 integers) int a[10];

e) 一個有10個指針的數組,每個指針是指向一個整型數(An array of 10 pointers to integers)int *a[10];

f) 一個指向有10個整型數數組的指針(A pointer to an array of 10 integers) int (*a)[10];

g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer as an argument andreturns an integer) int (*a)(int);

h) 一個有10個函數指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數( An array of ten pointers to functions that take an integer argumentand return an integer )int (*a[10])(int);

定義一個宏

請定義一個宏用於表示每一年有多少秒,忽視閏年的情況

#define SECOND_PER_YEAR (365 * 24 * 60 * 60UL)

給一整型變量a,寫兩段代碼,第一個設置a的bit3,第二個清除a的bit3.

|操作,當操作數爲1時,結果爲1,當操作數爲0時,結果不變;

&操作,當操作數爲1時,結果不變,當操作數爲0時,結果爲0

(第三個bit位在最低字節)

因此,設置a的bit 3爲1的方法就是將a和00001000作|操作,這樣其他位都不變,只有第3位變成1

清除a的bit3的方法就是將a和11110111作&操作,這樣第3位變成0,其他位不變

設置a的bit3代碼如下:

#include <stdio.h>

int main()

{

     int a;

     printf("請輸入一個整數");

     scanf("%d",&a);

     a=a|00000100;

     printf("%d",a);

     return 1;

}

 

清除a的bit3代碼如下:

#include <stdio.h>

int main()

{

      int a;

     printf("請輸入一個整數");

     scanf("%d",&a);

     a=a&11111011;

     printf("%d",a);

     return 1;

}

 

兩種方法用宏定義寫出swap(x,y)

方法一:算術運算法

a=a+b; 

b=a-b; 

a=a-b; 

 

方法二:邏輯運算法

a=a^b; 

b=a^b; 

a=a^b; 

 

宏定義swap(x, y),使之完成交換x,y的值 

#defineswap1(x, y) \ 

    (y) = (x) + (y); \ 

    (x) = (y) - (x); \ 

    (y) = (y) - (x); 

 

#defineswap2(x, y)\ 

    x = x^y;\ 

    y = x^y;\ 

    x = x^y;

 

 異或運算符

參與運算的兩個值,如果兩個相應位相同,則結果爲0,否則爲1。即:0^0=0, 1^0=1, 0^1=1, 1^1=0

例如:10100001^00010001=10110000

任何數異或自己,等於把自己置0

 

delete 和 delete [] 的區別

當調用delete的時候,系統會自動調用已分配的對象的析構函數。當我們用new [] 分配的對象是基本數據類型時,用delete和delete [] 沒有區別。但是,當分配的對象是自定義對象時,二者不能通用。一般來說使用new分配的對象,用delete來釋放。用new[] 分配的內存用delete [] 來逐個釋放。

 

大小值對比宏定義

#define __max(a,b) (((a) > (b)) ? (a) : (b))

#define __min(a,b) (((a) < (b)) ? (a) : (b))

 

C++調用C函數,爲什麼要加extern "C"?

C++語言支持函數重載,C語言不支持函數重載,函數被C++編譯器編譯後在

庫中的名字與C語言的不同,假設某個函數原型爲:

void foo(int x,inty);

該函數被C編譯器編譯後在庫中的名字爲:

_foo

而C++編譯器則會產生像:

_foo_int_int

之類的名字。爲了解決此類名字匹配的問題,C++提供了C鏈接交換指定符號extern "C"。加上extern "C"表示該函數的編譯與調用規則是C的規則

 

寫一段用來判斷內存存儲方式是大端還是小端的代碼

聯合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕鬆地獲得了CPU對內存採用Little-endian還是Big-endian模式讀寫。代碼如下:

intcheckCPUendian()

{

union

{

unsigned int a;

unsigned char b;

}c;

c.a = 1;

return (c.b = =1);

}

/*return 1 :little-endian, return 0:big-endian*/

 

定義一個返回值是指向函數的指針且有一個指向函數的指針作參數的函數

通用形式如下:

typedef int(*P)( ); // 定義一個函數指針P類型

P function( int(*p)( ) ); // 定義一個函數返回值P類型,且定義一個指向函數的指針p作參數

 

關鍵字const含意

聲明一個變量爲只讀。

下面的聲明都是什麼意思?

1)const int a; 2)int const a; 3)const int *a; 4)int * const a; 5) int const * const a ;

1,2一樣a爲只讀整形變量;3 指向一個只讀整形變量的指針;4 指向整形的只讀指針; 5 指向只讀整形的只讀指針

 

C語言實現設置一絕對地址爲0x1234的整型變量的值爲0xaa55

int *p;

p=(int *) 0x1234; // 把整型數0x1234強制轉換(typecast)爲一指針

*p=0xaa55;

 

中斷服務程序(Interrupt Service Routines,ISR)注意事項

1、ISR不能有返回值;

2、ISR不能傳遞參數;

3、ISR應該是短而高效的,在ISR中做浮點運算是不明智的

4、ISR中不應該有重入和性能上的問題,因此不應該使用pintf()函數。

 

typedef和#define的區別

#define在預編譯的時候處理作機械的字符替換。typedef在編譯的時候處理,並不是作簡單的字符替換。而是如同定義變量一樣聲明一個類型。然後用它去定義這種類型的變量。

 

反碼、補碼、原碼

負數的反碼:對原碼除符號位外的其餘各位逐位取反

負數的補碼:對反碼加1

正數的原碼、反碼、補碼都一樣

 

字符串轉整數

#include <stdio.h>

char str[6]="12345";

int string_to_int(char s[])

{

int i;

int sum=0;

for(i=0;s[i]!='\0';i++)

{

 sum=sum*10+s[i]-'0';

}

return sum;

}

 

int main(void)

{

printf("%d\n",string_to_int(str));

return 0;

}

整數轉字符串

#include <stdio.h>

#include <math.h>

#define LEN 4

char str[]=" ";

char *int_to_string(int given)

{

int i;

int temp;

for(i=0;i<LEN;i++) {

temp=given/pow(10,LEN-1-i); // 從最高位開始

given=given%((int) pow(10,LEN-1-i));

str[i]=temp+'0';

}

return str;

}

 

int main(void)

{

printf("%s\n",int_to_string(9876));

return 0;

}

 

用嵌套循環求1-100的素數

#include <stdio.h>

int main(void)

{

int i, j;

for (i = 1; i <= 100; i++) {

for (j = 2; j < i; j++)

if (i % j == 0)

break;

if (j == i)

printf("%d\n", i);

}

return 0;

}

 

計算一個數的階乘

遞歸實現:

int factorial(int n)

{

if (n == 0)

return 1;

else {

int recurse = factorial(n-1);

int result = n * recurse;

return result;

}

}

 

循環實現:

int factorial(int n)

{

int result = 1;

while (n > 0) {

result = result * n;

n = n - 1;

}

return result;

}

 

C語言實現冒泡排序算法(從大到小,從小到大)

#include<stdio.h>

#define LEN 5

int a[LEN]={5,4,3,2,1};

void bubble_sort(void)

{

int i,j,flag=1;

int temp;

for(i=1;(i<LEN)&&(flag==1);i++){

flag=0;

for(j=0;j<LEN-i;j++) {

if( a[j]>a[j+1] ){ // a[j]>a[j+1]從小到大;a[j]<a[j+1] 從大到小

flag=1;

temp=a[j];

a[j]=a[j+1];

a[j+1]=temp;

}

}

printf("%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4]);

}

}

//--------

int main(void)

{

bubble_sort();

return 0;

}

 

C語言實現插入排序算法(從大到小,從小到大).

#include<stdio.h>

#define LEN 5

int a[LEN]={7,4,8,4,5};

void insertion_sort(void)

{

int i,j,key;

for(j=1;j<LEN;j++){

printf("%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4]);

key=a[j];

i=j-1;

while( (i>=0) && (a[i]>key) ){ //a[i]>key 從小到大; a[i]<key 從大到小

a[i+1]=a[i];

i--;

}

a[i+1]=key;

}

printf("%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4]);

}

//-----

int main(void)

{

insertion_sort();

return 0;

}

 

TCP/IP協議集包括應用層,傳輸層,網絡層,網絡訪問層。

網絡層包括:    Internet協議(IP)     Internet控制信息協議(ICMP)    地址解析協議(ARP)    反向地址解析協議(RARP) 

網絡訪問層又稱作主機到網絡層(host-to-network).網絡訪問層的功能包括IP地址與物理地址硬件的映射,以及將IP封裝成幀.基於不同硬件類型的網絡接口,網絡訪問層定義了和物理介質的連接。

 

TCP與UDP區別

基本區別

1.基於連接與無連接

2.TCP要求系統資源較多,UDP較少;

3.UDP程序結構較簡單

4.流模式(TCP)與數據報模式(UDP);

5.TCP保證數據正確性,UDP可能丟包

6.TCP保證數據順序,UDP不保證

編程區別

通常我們在說到網絡編程時默認是指TCP編程,即用前面提到的socket函數創建一個socket用於TCP通訊,函數參數我們通常填爲SOCK_STREAM。即socket(PF_INET, SOCK_STREAM, 0),這表示建立一個socket用於流式網絡通訊。

SOCK_STREAM這種的特點是面向連接的,即每次收發數據之前必須通過connect建立連接,也是雙向的,即任何一方都可以收發數據,協議本身提供了一些保障機制保證它是可靠的、有序的,即每個包按照發送的順序到達接收方。

而SOCK_DGRAM這種是User DatagramProtocol協議的網絡通訊,它是無連接的,不可靠的,因爲通訊雙方發送數據後不知道對方是否已經收到數據,是否正常收到數據。任何一方建立一個socket以後就可以用sendto發送數據,也可以用recvfrom接收數據。根本不關心對方是否存在,是否發送了數據。它的特點是通訊速度比較快。大家都知道TCP是要經過三次握手的,而UDP沒有。

 

進程與線程的區別

通常操作系統把進程作爲分配資源的基本單位,而把線程作爲獨立運行和CPU獨立調度的基本單位。

內核鎖

多核處理器下,會存在多個進程處於內核態的情況,而在內核態下,進程是可以訪問所有內核數據的,因此要對共享數據進行保護,即互斥處理。

信號量mutex是sleep-waiting。就是說當沒有獲得mutex時,會有上下文切換,將自己、加到忙等待隊列中,直到另外一個線程釋放mutex並喚醒它,而這時CPU是空閒的,可以調度別的任務處理。

而自旋鎖spin lock是busy-waiting。就是說當沒有可用的鎖時,就一直忙等待並不停的進行鎖請求,直到得到這個鎖爲止。這個過程中cpu始終處於忙狀態,不能做別的任務。

例如在一個雙核的機器上有兩個線程(線程A和線程B),它們分別運行在Core0 和Core1上。用spin-lock,coer0上的線程就會始終佔用CPU。

另外一個值得注意的細節是spin lock耗費了更多的usertime。這就是因爲兩個線程分別運行在兩個核上,大部分時間只有一個線程能拿到鎖,所以另一個線程就一直在它運行的core上進行忙等待,CPU佔用率一直是100%;而mutex則不同,當對鎖的請求失敗後上下文切換就會發生,這樣就能空出一個核來進行別的運算任務了。

 volatile關鍵字

簡單地說作用就是防止編譯器對代碼進行優化。比如如下程序:

XBYTE[2]=0x55;

XBYTE[2]=0x56;

XBYTE[2]=0x57;

XBYTE[2]=0x58;

對外部硬件而言,上述四條語句分別表示不同的操作,會產生四種不同的動作,但是編譯器卻會對上述四條語句進行優化,認爲只有XBYTE[2]=0x58(即忽略前三條語句,只產生一條機器代碼)。如果鍵入volatile,則編譯器會逐一地進行編譯併產生相應的機器代碼(產生四條代碼)。

精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裏的備份。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章