⑴ c語言基本問題有哪些
一、C語言規定總是從main()開始執行的(這個函數也叫「主函數」)。因此,你發來的題目中的(1、6、8)敘述都是錯誤的,都應該選擇F。
二、第2題中,C語言對其數據在內存中所佔用的實際位元組數,隨著程序中聲明的數據類型以及數據的多少而變化,C語言本身並沒有明確規定。這題應該選F。
三、第3題,C語言中強制類型轉換,僅對轉換的語句有效,而不會改變所轉換變數的原有數據類型,這是正確的,應該選T。
四、第4題,i=8,j=10;printf("%d,%d,%d,%d\n",i,j,++i,j++);實際上是一個程序執行類題目,執行這一句時,先取得ij變數的值,其中有一個++i(先自增),一個j++(後自增),先自增的i先加上1,也就是i=8+1=9,而後自增的j在列印之後再加1,所以列印時仍是j=10。所以列印出來是:9 10 9 10。這是正確的。
五、第5題「C語言中放在「」之間的內容都被視為字元串的一個構成部分,都可以在屏幕上原樣顯示」的說法是錯誤的。舉一個例子就可以了:print("%d",8);是列印不出來%d的,它只能列印出來8。所以它是錯的。
六、第7題,設x、t均為int型變數,則執行語句"x = 10;t = x && x >10;"後,t的值為,這個題目好似沒有寫完,成了填空題了,現在來看計算過程,t = x && x >10,根據計算的優先順序,>號是6級,&&是11級,先計算x >10,因為x=10,故x>10是不成立的,所以它的值是0,第二步再計算x && 0=10 && 0=0。t的值最後應該是0。
希望對你有所幫助。
⑵ 作為C語言初學者,經常遇見哪些語法錯誤
這里常見會見到一些同學經常犯這種錯誤,scanf(「...」, 參數1, 參數2, ...);其中參數輸入是指針類型,所以示例中需要b需要取地址,為什麼char a[100]不用取地址呢?因為char a[100]可以看做指針,只需要把a的首地址寫入即可。
C語言常見語法錯誤
跟一些同學說了一下,他彷彿又有點明白了。然而他又說怎麼又是有錯誤的,我明明按照你的要求參數寫入時指針類型。那同學還特意地指出程序裡面說:我申請了一個結構體指d,填入的「d->b」參數不是指針嗎?聽到他這樣說,有問題當然要糾正啦!語重心長地對他說,大哥!你認真看一下,d->b應該是int類型,而不是指針類型吧?他聽了好像不怎麼明白,我就舉了一個例子,結構體好像是一個容器,容器裡面存放著類型變數,而通過結構體容器找裡面的內容是比如找的是結構體成員b,那b的類型是int型,具體怎麼找用d->b找到b變數,那d->b是什麼類型呢?當然是d結構體所指向與b的int類型。
C語言常見語法錯誤
這一句沒語法錯誤,卻是最多初學者這樣去寫的,他們就會說,為什麼我輸入一個數字後按回車怎麼沒反應的呢?咋一看程序才發現多了一個」\n」,具體原理是這樣的,當你程序是scanf(「%d」, &i)輸入數字後回車是可以輸入的,但是變成scanf(「%d\n」, &i);時候就需要回車兩次,因為\n需要格式化輸入。
C語言常見語法錯誤
頭文件寫錯也是很多人犯的,比如卻後綴『.h』,系統頭文件需要使用<>括住,而自定義頭文件使用」 」,在linux C裡面<>和」 」還是有區別的。
正確寫法是:
#include <stdio.h>
#include <string.h>
#include 「func.h」
C語言常見語法錯誤
這里混淆了字元常量與字元串常量,字元常量是使用單引號括起來的單字元,字元串常量才是使用雙引號,正確寫法是char c = 『a』;或者char *c = 「a」;
C語言常見語法錯誤
這里也是很多初學者犯的錯誤,忽略『=』和『==』的區別。在C語言中『=』是賦值運算符,『==』是關系運算符,顯然這里做的是i是否等於0的判斷,這里應該改成if(i == 0) i++;
C語言常見語法錯誤
這里的問題也是初學者犯得非常多的錯誤,不加分號或多加分號。很多學生都會問,我看了幾次程序,確定沒什麼問題的啦!還是對著你的示常式序敲的,不可能錯的。認真地幫他看了一下,原來都是少加分號和多加分號了。int i = 0; 需要加分號,而if(i == 0)和for循環後面不需要加分號,因為如果加了分號,if語句就失去判斷的作用而for就會失去循環的作用。因為『;』代表的是結束。
C語言常見語法錯誤
還有一些格式上的錯誤、關鍵詞寫不完整、區分大小寫。正確應該是scanf(「%d%d%d」, a, b, c);
C語言常見語法錯誤
總結一下,學習嵌入式編程特別是在C語言上要學會如何找錯誤,一般有錯誤都是在編譯輸出終端裡面找,會提示那一行出錯或者錯的是什麼編譯器都會大概告訴你,學會找出問題所在再去解決它才是我們真正需要的。
⑶ c語言常見面試題
C語言面試常見問題
預處理器(Preprocessor)
1 . 用預處理指令#define 聲明一個常數,用以表明1年中有多少秒(忽略閏年問題)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
我在這想看到幾件事情:
1) #define 語法的基本知識(例如:不能以分號結束,括弧的使用,等等)
2)懂得預處理器將為你計算常數表達式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。
3) 意識到這個表達式將使一個16位機的整型數溢出-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數。
4) 如果你在你的表達式中用到UL(表示無符號長整型),那麼你有了一個好的起點。記住,第一印象很重要。
2 . 寫一個"標准"宏MIN ,這個宏輸入兩個參數並返回較小的一個。
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
這個測試是為下面的目的而設的:
1) 標識#define在宏中應用的基本知識。這是很重要的。因為在 嵌入(inline)操作符 變為標准C的一部分之前,宏是方便產生嵌入代碼的唯一方法,對於嵌入式系統來說,為了能達到要求的性能,嵌入代碼經常是必須的方法。
2)三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產生比if-then-else更優化的代碼,了解這個用法是很重要的。
3) 懂得在宏中小心地把參數用括弧括起來
4) 我也用這個問題開始討論宏的副作用,例如:當你寫下面的代碼時會發生什麼事?
least = MIN(*p++, b);
3. 預處理器標識#error的目的是什麼?
如果你不知道答案,請看參考文獻1。這問題對區分一個正常的伙計和一個書獃子是很有用的。只有書獃子才會讀C語言課本的附錄去找出象這種問題的答案。當然如果你不是在找一個書獃子,那麼應試者最好希望自己不要知道答案。
死循環(Infinite loops)
4. 嵌入式系統中經常要用到無限循環,你怎麼樣用C編寫死循環呢?
這個問題用幾個解決方案。我首選的方案是:
while(1)
{
}
一些程序員更喜歡如下方案:
for(;;)
{
}
這個實現方式讓我為難,因為這個語法沒有確切表達到底怎麼回事。如果一個應試者給出這個作為方案,我將用這個作為一個機會去探究他們這樣做的基本原理。如果他們的基本答案是:"我被教著這樣做,但從沒有想到過為什麼。"這會給我留下一個壞印象。
第三個方案是用 goto
Loop:
...
goto Loop;
應試者如給出上面的方案,這說明或者他是一個匯編語言程序員(這也許是好事)或者他是一個想進入新領域的BASIC/FORTRAN程序員。
數據聲明(Data declarations)
5. 用變數a給出下面的定義
a) 一個整型數(An integer)
b)一個指向整型數的指針( A pointer to an integer)
c)一個指向指針的的指針,它指向的指針是指向一個整型數( A pointer to a pointer to an intege)r
d)一個有10個整型數的數組( An array of 10 integers)
e) 一個有10個指針的數組,該指針是指向一個整型數的。(An array of 10 pointers to integers)
f) 一個指向有10個整型數數組的指針( A pointer to an array of 10 integers)
g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數( An array of ten pointers to functions that take an integer argument and return an integer )
答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
人們經常聲稱這里有幾個問題是那種要翻一下書才能回答的問題,我同意這種說法。當我寫這篇文章時,為了確定語法的正確性,我的確查了一下書。但是當我被面試的時候,我期望被問到這個問題(或者相近的問題)。因為在被面試的這段時間里,我確定我知道這個問題的答案。應試者如果不知道所有的答案(或至少大部分答案),那麼也就沒有為這次面試做准備,如果該面試者沒有為這次面試做准備,那麼他又能為什麼出准備呢?
Static
6. 關鍵字static的作用是什麼?
這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
1)在函數體,一個被聲明為靜態的變數在這一函數被調用過程中維持其值不變。
2) 在模塊內(但在函數體外),一個被聲明為靜態的變數可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變數。
3) 在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用。
大多數應試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,因為他顯然不懂得本地化數據和代碼范圍的好處和重要性。
Const
7.關鍵字const有什麼含意?
我只要一聽到被面試者說:"const意味著常數",我就知道我正在和一個業余者打交道。去年Dan Saks已經在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什麼和不能做什麼.如果你從沒有讀到那篇文章,只要能說出const意味著"只讀"就可以了。盡管這個答案不是完全的答案,但我接受它作為一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)
如果應試者能正確回答這個問題,我將問他一個附加的問題:
下面的聲明都是什麼意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
/******/
前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最後一個意味著a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。如果應試者能正確回答這些問題,那麼他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字 const,也還是能很容易寫出功能正確的程序,那麼我為什麼還要如此看重關鍵字const呢?我也如下的幾下理由:
1) 關鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數為常量是為了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)
2) 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。
3) 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。
Volatile
8. 關鍵字volatile有什麼含意?並給出三個不同的例子。
一個定義為volatile的變數是說這變數可能會被意想不到地改變,這樣,編譯器就不會去假設這個變數的值了。精確地說就是,優化器在用到這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用保存在寄存器里的備份。下面是volatile變數的幾個例子:
1) 並行設備的硬體寄存器(如:狀態寄存器)
2) 一個中斷服務子程序中會訪問到的非自動變數(Non-automatic variables)
3) 多線程應用中被幾個任務共享的變數
回答不出這個問題的人是不會被僱傭的。我認為這是區分C程序員和嵌入式系統程序員的最基本的問題。搞嵌入式的傢伙們經常同硬體、中斷、RTOS等等打交道,所有這些都要求用到volatile變數。不懂得volatile的內容將會帶來災難。
假設被面試者正確地回答了這是問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這傢伙是不是直正懂得volatile完全的重要性。
1)一個參數既可以是const還可以是volatile嗎?解釋為什麼。
2); 一個指針可以是volatile 嗎?解釋為什麼。
3); 下面的函數有什麼錯誤:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1)是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
2); 是的。盡管這並不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
3) 這段代碼有點變態。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
位操作(Bit manipulation)
9. 嵌入式系統總是要用戶對變數或寄存器進行位操作。給定一個整型變數a,寫兩段代碼,第一個設置a的bit 3,第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。
對這個問題有三種基本的反應
1)不知道如何下手。該被面者從沒做過任何嵌入式系統的工作。
2) 用bit fields。Bit fields是被扔到C語言死角的東西,它保證你的代碼在不同編譯器之間是不可移植的,同時也保證了的你的代碼是不可重用的。我最近不幸看到 Infineon為其較復雜的通信晶元寫的驅動程序,它用到了bit fields因此完全對我無用,因為我的編譯器用其它的方式來實現bit fields的。從道德講:永遠不要讓一個非嵌入式的傢伙粘實際硬體的邊。
3) 用 #defines 和 bit masks 操作。這是一個有極高可移植性的方法,是應該被用到的方法。最佳的解決方案如下:
#define BIT3 (0x1 << 3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &= ~BIT3;
}
一些人喜歡為設置和清除值而定義一個掩碼同時定義一些說明常數,這也是可以接受的。我希望看到幾個要點:說明常數、|=和&=~操作。
訪問固定的內存位置(Accessing fixed memory locations)
10. 嵌入式系統經常具有要求程序員去訪問某特定的內存位置的特點。在某工程中,要求設置一絕對地址為0x67a9的整型變數的值為0xaa66。編譯器是一個純粹的ANSI編譯器。寫代碼去完成這一任務。
這一問題測試你是否知道為了訪問一絕對地址把一個整型數強制轉換(typecast)為一指針是合法的。這一問題的實現方式隨著個人風格不同而不同。典型的類似代碼如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
A more obscure approach is:
一個較晦澀的方法是:
*(int * const)(0x67a9) = 0xaa55;
即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。
中斷(Interrupts)
11. 中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴展—讓標准C支持中斷。具代表事實是,產生了一個新的關鍵字 __interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一個中斷服務子程序(ISR),請評論一下這段代碼的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
這個函數有太多的錯誤了,以至讓人不知從何說起了:
1)ISR 不能返回一個值。如果你不懂這個,那麼你不會被僱用的。
2) ISR 不能傳遞參數。如果你沒有看到這一點,你被僱用的機會等同第一項。
3) 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的。
4) 與第三點一脈相承,printf()經常有重入和性能上的問題。如果你丟掉了第三和第四點,我不會太為難你的。不用說,如果你能得到後兩點,那麼你的被僱用前景越來越光明了。
代碼例子(Code examples)
12 . 下面的代碼輸出是什麼,為什麼?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
這個問題測試你是否懂得C語言中的整數自動轉換原則,我發現有些開發者懂得極少這些東西。不管如何,這無符號整型問題的答案是輸出是 ">6"。原因是當表達式中存在有符號類型和無符號類型時所有的操作數都自動轉換為無符號類型。因此-20變成了一個非常大的正整數,所以該表達式計算出的結果大於6。這一點對於應當頻繁用到無符號數據類型的嵌入式系統來說是豐常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。
13. 評價下面的代碼片斷:
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */
對於一個int型不是16位的處理器為說,上面的代碼是不正確的。應編寫如下:
unsigned int compzero = ~0;
這一問題真正能揭露出應試者是否懂得處理器字長的重要性。在我的經驗里,好的嵌入式程序員非常准確地明白硬體的細節和它的局限,然而PC機程序往往把硬體作為一個無法避免的煩惱。
到了這個階段,應試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應試者不是很好,那麼這個測試就在這里結束了。但如果顯然應試者做得不錯,那麼我就扔出下面的追加問題,這些問題是比較難的,我想僅僅非常優秀的應試者能做得不錯。提出這些問題,我希望更多看到應試者應付問題的方法,而不是答案。不管如何,你就當是這個娛樂吧...
動態內存分配(Dynamic memory allocation)
14. 盡管不像非嵌入式計算機那麼常見,嵌入式系統還是有從堆(heap)中動態分配內存的過程的。那麼嵌入式系統中,動態分配內存可能發生的問題是什麼?
這里,我期望應試者能提到內存碎片,碎片收集的問題,變數的持行時間等等。這個主題已經在ESP雜志中被廣泛地討論過了(主要是 P.J. Plauger, 他的解釋遠遠超過我這里能提到的任何解釋),所有回過頭看一下這些雜志吧!讓應試者進入一種虛假的安全感覺後,我拿出這么一個小節目:
下面的代碼片段的輸出是什麼,為什麼?
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
puts("Got a null pointer");
else
puts("Got a valid pointer");
這是一個有趣的問題。最近在我的一個同事不經意把0值傳給了函數malloc,得到了一個合法的指針之後,我才想到這個問題。這就是上面的代碼,該代碼的輸出是"Got a valid pointer"。我用這個來開始討論這樣的一問題,看看被面試者是否想到庫常式這樣做是正確。得到正確的答案固然重要,但解決問題的方法和你做決定的基本原理更重要些。
Typedef
15 Typedef 在C語言中頻繁用以聲明一個已經存在的數據類型的同義字。也可以用預處理器做類似的事。例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個指向結構s指針。哪種方法更好呢?(如果有的話)為什麼?
這是一個非常微妙的問題,任何人答對這個問題(正當的原因)是應當被恭喜的。答案是:typedef更好。思考下面的例子:
dPS p1,p2;
tPS p3,p4;
第一個擴展為
struct s * p1, p2;
.
上面的代碼定義p1為一個指向結構的指,p2為一個實際的結構,這也許不是你想要的。第二個例子正確地定義了p3 和p4 兩個指針。
晦澀的語法
16 . C語言同意一些令人震驚的結構,下面的結構是合法的嗎,如果是它做些什麼?
int a = 5, b = 7, c;
c = a+++b;
這個問題將做為這個測驗的一個愉快的結尾。不管你相不相信,上面的例子是完全合乎語法的。問題是編譯器如何處理它?水平不高的編譯作者實際上會爭論這個問題,根據最處理原則,編譯器應當能處理盡可能所有合法的用法。因此,上面的代碼被處理成:
c = a++ + b;
因此, 這段代碼持行後a = 6, b = 7, c = 12。
如果你知道答案,或猜出正確答案,做得好。如果你不知道答案,我也不把這個當作問題。我發現這個問題的最大好處是這是一個關於代碼編寫風格,代碼的可讀性,代碼的可修改性的好的話題。
⑷ c語言指針面試常見問題
c語言指針面試常見問題
指針的使用,一直是c語言面試題中必考的部分,因為指針本身使用的復雜性與普適性,所以考點非常多,而且也可以與其他知識相互結合,因此我們將會使用五篇專題的篇幅來介紹指針。
分析下面的程序,指出程序中的錯誤:
本題解析
沒有正確為str分配內存空間,將會發生異常。問題出在將一個字元串復制進一個字元變數指針所指地址。雖然編譯的時候沒有報錯,但是在運行過程中,因為越界訪問了未被分配的內存,而導致段錯誤。
相關知識點
在處理與指針相關的問題時,首先需要搞明白的就是內存,因為指針操作的就是內存。
第一個,就是內存的分區。這也是經常會被考察的一個考點。
寫出內存分為幾大區域
對於這個問題,有幾種不同的說法,有的說內存分為五大分區,有的說分為四大分區,我們先來看五大分區的說法:
認為內存分為五大分區的人,通常會這樣劃分:
1、BSS段( bss segment )
通常是指用來存放程序中未初始化的'全局變數和靜態變數 (這里注意一個問題:一般的書上都會說全局變數和靜態變數是會自動初始化的,那麼哪來的未初始化的變數呢?變數的初始化可以分為顯示初始化和隱式初始化,全局變數和靜態變數如果程序員自己不初始化的話的確也會被初始化,那就是不管什麼類型都初始化為0,這種沒有顯示初始化的就 是我們這里所說的未初始化。既然都是0那麼就沒必要把每個0都存儲起來,從而節省磁碟空間,這是BSS的主要作用)的一塊內存區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態內存分配。 BSS節不包含任何數據,只是簡單的維護開始和結束的地址,即總大小。以便內存區能在運行時分配並被有效地清零。BSS節在應用程序的二進制映象文件中並不存在,即不佔用 磁碟空間 而只在運行的時候佔用內存空間 ,所以如果全局變數和靜態變數未初始化那麼其可執行文件要小很多。
2、數據段(data segment)
通常是指用來存放程序中已經初始化的全局變數和靜態變數的一塊內存區域。數據段屬於靜態內存分配,可以分為只讀數據段和讀寫數據段。字元串常量等,但一般都是放在只讀數據段中。
3、代碼段(code segment/text segment)
通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,並且內存區域通常屬於只讀, 某些架構也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數變數,例如字元串常量等,但一般都是放在只讀數據段中 。
4、堆(heap)
堆是用於存放進程運行中被動態分配的內存段,它的大小並不固定,可動態擴張或 縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張); 當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)
5、棧 (stack)
棧又稱堆棧, 是用戶存放程序臨時創建的局部變數,也就是說我們函數括弧「{}」 中定義的變數(但不包括static聲明的變數,static意味著在數據段中存放變 量)。除此以外, 在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的返回值 也會被存放回棧中。由於棧的先進先出特點,所以 棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的內存區。
而四大分區的說法,則這么認為:
1、堆區:
由程序員手動申請,手動釋放,若不手動釋放,程序結束後由系統回收,生命周期是整個程序運行期間。使用malloc或者new進行堆的申請,堆的總大小為機器的虛擬內存的大小。
說明:new操作符本質上是使用了malloc進行內存的申請,new和malloc的區別如下:
(1)malloc是C語言中的函數,而new是C++中的操作符。
(2)malloc申請之後返回的類型是void*,而new返回的指針帶有類型。
(3)malloc只負責內存的分配而不會調用類的構造函數,而new不僅會分配內存,而且會自動調用類的構造函數。
2、棧區:
由系統進行內存的管理。主要存放函數的參數以及局部變數。在函數完成執行,系統自行釋放棧區內存,不需要用戶管理。整個程序的棧區的大小可以在編譯器中由用戶自行設定,VS中默認的棧區大小為1M,可通過VS手動更改棧的大小。64bits的Linux默認棧大小為10MB,可通過ulimit -s臨時修改。
3、靜態存儲區:
靜態存儲區內的變數在程序編譯階段已經分配好內存空間並初始化。這塊內存在程序的整個運行期間都存在,它主要存放靜態變數、全局變數和常量。
注意:
(1)這里不區分初始化和未初始化的數據區,是因為靜態存儲區內的變數若不顯示初始化,則編譯器會自動以默認的方式進行初始化,即靜態存儲區內不存在未初始化的變數。
(2)靜態存儲區內的常量分為常變數和字元串常量,一經初始化,不可修改。靜態存儲內的常變數是全局變數,與局部常變數不同,區別在於局部常變數存放於棧,實際可間接通過指針或者引用進行修改,而全局常變數存放於靜態常量區則不可以間接修改。
(3)字元串常量存儲在靜態存儲區的常量區,字元串常量的名稱即為它本身,屬於常變數。
(4)數據區的具體劃分,有利於我們對於變數類型的理解。不同類型的變數存放的區域不同。後面將以實例代碼說明這四種數據區中具體對應的變數。
4、代碼區:
存放程序體的二進制代碼。比如我們寫的函數,都是在代碼區的。
通過上面的不同說法,我們也可以看出,這兩種說法本身沒有優劣之分,具體的內存劃分也跟編譯器有很大的關系,因此這兩種說法都是可以接受的,搞明白內存的分區之後,指針的使用才能夠更加的靈活。
;⑸ C語言編程都有哪些常見錯誤呢
1,輸入錯誤,這是很多新手長患的一個錯誤。
2,語法錯誤,由於很多新手對語言的語法不是很熟悉,所以難免會出現很多錯誤。這就要就要多練,只有這樣才能熟悉語法,也就可以避免錯誤了。
3,對要解決的問題分析不夠清晰,在寫語句的時候會發現得不到想要的結果,這就要求在寫程序時注重對問題的分析
以上這三點就是寫程序時最長患的錯誤了,希望你可以努力
⑹ C語言程序常見的錯誤有哪些
/..com/question/186344584.html>
1.書寫標識符時,忽略了大小寫字母的區別。
main()
{
int a=5;
printf("%d",A);
}
編譯程序把a和A認為是兩個不同的變數名,而顯示出錯信息。C認為大寫字母和小寫字母是兩個不同的字元。習慣上,符號常量名用大寫,變數名用小寫表示,以增加可讀性。
2.忽略了變數的類型,進行了不合法的運算。
main()
{
float a,b;
printf("%d",a%b);
}
%是求余運算,得到a/b的整余數。整型變數a和b可以進行求余運算,而實型變數則不允許進行「求余」運算。
3.將字元常量與字元串常量混淆。
char c;
c="a";
在這里就混淆了字元常量與字元串常量,字元常量是由一對單引號括起來的單個字元,字元串常量是一對雙引號括起來的字元序列。C規定以「\」作字元串結束標志,它是由系統自動加上的,所以字元串「a」實際上包含兩個字元:『a'和『\',而把它賦給一個字元變數是不行的。
4.忽略了「=」與「==」的區別。
在許多高級語言中,用「=」符號作為關系運算符「等於」。如在BASIC程序中可以寫
if (a=3) then …
但C語言中,「=」是賦值運算符,「==」是關系運算符。如:
if (a==3) a=b;
前者是進行比較,a是否和3相等,後者表示如果a和3相等,把b值賦給a。由於習慣問題,初學者往往會犯這樣的錯誤。
5.忘記加分號。
分號是C語句中不可缺少的一部分,語句末尾必須有分號。
a=1
b=2
編譯時,編譯程序在「a=1」後面沒發現分號,就把下一行「b=2」也作為上一行語句的一部分,這就會出現語法錯誤。改錯時,有時在被指出有錯的一行中未發現錯誤,就需要看一下上一行是否漏掉了分號。
{ z=x+y;
t=z/100;
printf("%f",t);
}
對於復合語句來說,最後一個語句中最後的分號不能忽略不寫(這是和PASCAL不同的)。
6.多加分號。
對於一個復合語句,如:
{ z=x+y;
t=z/100;
printf("%f",t);
};
復合語句的花括弧後不應再加分號,否則將會畫蛇添足。
又如:
if (a%3==0);
I++;
本是如果3整除a,則I加1。但由於if (a%3==0)後多加了分號,則if語句到此結束,程序將執行I++語句,不論3是否整除a,I都將自動加1。
再如:
for (I=0;I<5;I++);
{scanf("%d",&x);
printf("%d",x);}
本意是先後輸入5個數,每輸入一個數後再將它輸出。由於for()後多加了一個分號,使循環體變為空語句,此時只能輸入一個數並輸出它。
7.輸入變數時忘記加地址運算符「&」。
int a,b;
scanf("%d%d",a,b);
這是不合法的。Scanf函數的作用是:按照a、b在內存的地址將a、b的值存進去。「&a」指a在內存中的地址。
8.輸入數據的方式與要求不符。①scanf("%d%d",&a,&b);
輸入時,不能用逗號作兩個數據間的分隔符,如下面輸入不合法:
3,4
輸入數據時,在兩個數據之間以一個或多個空格間隔,也可用回車鍵,跳格鍵tab。
②scanf("%d,%d",&a,&b);
C規定:如果在「格式控制」字元串中除了格式說明以外還有其它字元,則在輸入數據時應輸入與這些字元相同的字元。下面輸入是合法的:
3,4
此時不用逗號而用空格或其它字元是不對的。
3 4 3:4
又如:
scanf("a=%d,b=%d",&a,&b);
輸入應如以下形式:
a=3,b=4
9.輸入字元的格式與要求不一致。
在用「%c」格式輸入字元時,「空格字元」和「轉義字元」都作為有效字元輸入。
scanf("%c%c%c",&c1,&c2,&c3);
如輸入a b c
字元「a」送給c1,字元「 」送給c2,字元「b」送給c3,因為%c只要求讀入一個字元,後面不需要用空格作為兩個字元的間隔。
10.輸入輸出的數據類型與所用格式說明符不一致。
例如,a已定義為整型,b定義為實型
a=3;b=4.5;
printf("%f%d\n",a,b);
編譯時不給出出錯信息,但運行結果將與原意不符。這種錯誤尤其需要注意。
⑺ c語言常見問題有哪些
1.書寫標識符時,忽略了大小寫字母的區別。
main()
{
int
a=5;
printf("%d",A);
}
編譯程序把a和A認為是兩個不同的變數名,而顯示出錯信息。C認為大寫字母和小寫字母是兩個不同的字元。習慣上,符號常量名用大寫,變數名用小寫表示,以增加可讀性。
2.忽略了變數的類型,進行了不合法的運算。
main()
{
float
a,b;
printf("%d",a%b);
}
%是求余運算,得到a/b的整余數。整型變數a和b可以進行求余運算,而實型變數則不允許進行「求余」運算。
3.將字元常量與字元串常量混淆。
char
c;
c="a";
在這里就混淆了字元常量與字元串常量,字元常量是由一對單引號括起來的單個字元,字元串常量是一對雙引號括起來的字元序列。C規定以「\」作字元串結束標志,它是由系統自動加上的,所以字元串「a」實際上包含兩個字元:『a'和『\',而把它賦給一個字元變數是不行的。
4.忽略了「=」與「==」的區別。
在許多高級語言中,用「=」符號作為關系運算符「等於」。如在BASIC程序中可以寫
if
(a=3)
then
…
但C語言中,「=」是賦值運算符,「==」是關系運算符。如:
if
(a==3)
a=b;
前者是進行比較,a是否和3相等,後者表示如果a和3相等,把b值賦給a。由於習慣問題,初學者往往會犯這樣的錯誤。
5.忘記加分號。
分號是C語句中不可缺少的一部分,語句末尾必須有分號。
a=1
b=2
編譯時,編譯程序在「a=1」後面沒發現分號,就把下一行「b=2」也作為上一行語句的一部分,這就會出現語法錯誤。改錯時,有時在被指出有錯的一行中未發現錯誤,就需要看一下上一行是否漏掉了分號。
{
z=x+y;
t=z/100;
printf("%f",t);
}
對於復合語句來說,最後一個語句中最後的分號不能忽略不寫(這是和PASCAL不同的)。
6.多加分號。
對於一個復合語句,如:
{
z=x+y;
t=z/100;
printf("%f",t);
};
復合語句的花括弧後不應再加分號,否則將會畫蛇添足。
又如:
if
(a%3==0);
I++;
本是如果3整除a,則I加1。但由於if
(a%3==0)後多加了分號,則if語句到此結束,程序將執行I++語句,不論3是否整除a,I都將自動加1。
再如:
for
(I=0;I<5;I++);
{scanf("%d",&x);printf("%d",x);}
本意是先後輸入5個數,每輸入一個數後再將它輸出。由於for()後多加了一個分號,使循環體變為空語句,此時只能輸入一個數並輸出它。
7.輸入變數時忘記加地址運算符「&」。
int
a,b;
scanf("%d%d",a,b);
這是不合法的。Scanf函數的作用是:按照a、b在內存的地址將a、b的值存進去。「&a」指a在內存中的地址。
8.輸入數據的方式與要求不符。①scanf("%d%d",&a,&b);
輸入時,不能用逗號作兩個數據間的分隔符,如下面輸入不合法:
3,4
輸入數據時,在兩個數據之間以一個或多個空格間隔,也可用回車鍵,跳格鍵tab。
②scanf("%d,%d",&a,&b);
C規定:如果在「格式控制」字元串中除了格式說明以外還有其它字元,則在輸入數據時應輸入與這些字元相同的字元。下面輸入是合法的:
3,4
此時不用逗號而用空格或其它字元是不對的。
3
4
3:4
又如:
scanf("a=%d,b=%d",&a,&b);
輸入應如以下形式:
a=3,b=4
9.輸入字元的格式與要求不一致。
在用「%c」格式輸入字元時,「空格字元」和「轉義字元」都作為有效字元輸入。
scanf("%c%c%c",&c1,&c2,&c3);
如輸入a
b
c
字元「a」送給c1,字元「
」送給c2,字元「b」送給c3,因為%c只要求讀入一個字元,後面不需要用空格作為兩個字元的間隔。
10.輸入輸出的數據類型與所用格式說明符不一致。
例如,a已定義為整型,b定義為實型
a=3;b=4.5;
printf("%f%d\n",a,b);
編譯時不給出出錯信息,但運行結果將與原意不符。這種錯誤尤其需要注意。
⑻ c語言問題
您好,c語言經典100題:
【程序1】
題目:有1,2,3,4個數字,能組成多少個互不相同且無重復數字的三位數 都是多少
1.程序分析:可填在百位,十位,個位的數字都是1,2,3,4.組成所有的排列後再去
掉不滿足條件的排列.
2.程序源代碼:
main()
{
int i,j,k;
printf("\n");
for(i1;i<5;i++) /*以下為三重循環*/
for(j1;j<5;j++)
for (k1;k<5;k++)
{
if (i!k&&i!j&&j!k) /*確保i,j,k三位互不相同*/
printf("%d,%d,%d\n",i,j,k);
}
}
【程序2】
題目:企業發放的獎金根據利潤提成.利潤(i)低於或等於10萬元時,獎金可提10%;利潤高
於10萬元,低於20萬元時,低於10萬元的部分按10%提成,高於10萬元的部分,可可提
成7.5%;20萬到40萬之間時,高於20萬元的部分,可提成5%;40萬到60萬之間時高於
40萬元的部分,可提成3%;60萬到100萬之間時,高於60萬元的部分,可提成1.5%,高於
100萬元時,超過100萬元的部分按1%提成,從鍵盤輸入當月利潤i,求應發放獎金總數
1.程序分析:請利用數軸來分界,定位.注意定義時需把獎金定義成長整型.
2.程序源代碼:
main()
{
long int i;
int bonus1,bonus2,bonus4,bonus6,bonus10,bonus;
scanf("%ld",&i);
bonus1100000*0.1;bonus2bonus1+100000*0.75;
bonus4bonus2+200000*0.5;
bonus6bonus4+200000*0.3;
bonus10bonus6+400000*0.15;
if(i<100000)
bonusi*0.1;
else if(i<200000)
bonusbonus1+(i-100000)*0.075;
else if(i<400000)
bonusbonus2+(i-200000)*0.05;
else if(i<600000)
bonusbonus4+(i-400000)*0.03;
else if(i<1000000)
bonusbonus6+(i-600000)*0.015;
else
bonusbonus10+(i-1000000)*0.01;
printf("bonus%d",bonus);
}
【程序3】
題目:一個整數,它加上100後是一個完全平方數,再加上168又是一個完全平方數,請問該數是多少
1.程序分析:在10萬以內判斷,先將該數加上100後再開方,再將該數加上268後再開方,如果開方後
的結果滿足如下條件,即是結果.請看具體分析:
2.程序源代碼:
#include "math.h"
main()
{
long int i,x,y,z;
for (i1;i2)/*如果是閏年且月份大於2,總天數應該加一天*/
sum++;
printf("it is the %dth day.",sum);}
【程序4】
題目:輸入某年某月某日,判斷這一天是這一年的第幾天?
1.程序分析:以3月5日為例,應該先把前兩個月的加起來,然後再加上5天即本年的第幾天,特殊
情況,閏年且輸入月份大於3時需考慮多加一天。
2.程序源代碼:
main()
{
int day,month,year,sum,leap;
printf("\nplease input year,month,day\n");
scanf("%d,%d,%d",&year,&month,&day);
switch(month)/*先計算某月以前月份的總天數*/
{
case 1:sum0;break;
case 2:sum31;break;
case 3:sum59;break;
case 4:sum90;break;
case 5:sum120;break;
case 6:sum151;break;
case 7:sum181;break;
case 8:sum212;break;
case 9:sum243;break;
case 10:sum273;break;
case 11:sum304;break;
case 12:sum334;break;
default:printf("data error");break;
}
sumsum+day; /*再加上某天的天數*/
if(year%4000||(year%40&&year%100!0))/*判斷是不是閏年*/
leap1;
else
leap0;
if(leap1&&month>2)/*如果是閏年且月份大於2,總天數應該加一天*/
sum++;
printf("It is the %dth day.",sum);}
【程序5】
題目:輸入三個整數x,y,z,請把這三個數由小到大輸出.
1.程序分析:我們想辦法把最小的數放到x上,先將x與y進行比較,如果x>y則將x與y的值進行交換,
然後再用x與z進行比較,如果x>z則將x與z的值進行交換,這樣能使x最小.
2.程序源代碼:
main()
{
int x,y,z,t;
scanf("%d%d%d",&x,&y,&z);
if (x>y)
{tx;xy;yt;} /*交換x,y的值*/
if(x>z)
{tz;zx;xt;}/*交換x,z的值*/
if(y>z)
{ty;yz;zt;}/*交換z,y的值*/
printf("small to big: %d %d %d\n",x,y,z);
}
【程序6】
題目:用*號輸出字母c的圖案.
1.程序分析:可先用'*'號在紙上寫出字母c,再分行輸出.
2.程序源代碼:
#include "stdio.h"
main()
{
printf("hello c-world!\n");
printf(" ****\n");
printf(" *\n");
printf(" * \n");
printf(" ****\n");
}
【程序7】
題目:輸出特殊圖案,請在c環境中運行,看一看,very beautiful!
1.程序分析:字元共有256個.不同字元,圖形不一樣.
2.程序源代碼:
#include "stdio.h"
main()
{
char a176,b219;
printf("%c%c%c%c%c\n",b,a,a,a,b);
printf("%c%c%c%c%c\n",a,b,a,b,a);
printf("%c%c%c%c%c\n",a,a,b,a,a);
printf("%c%c%c%c%c\n",a,b,a,b,a);
printf("%c%c%c%c%c\n",b,a,a,a,b);}
【程序8】
題目:輸出9*9口訣.
1.程序分析:分行與列考慮,共9行9列,i控制行,j控制列.
2.程序源代碼:
#include "stdio.h"
main()
{
int i,j,result;
printf("\n");
for (i1;i<10;i++)
{ for(j1;j<10;j++)
{
resulti*j;
printf("%d*%d%-3d",i,j,result);/*-3d表示左對齊,佔3位*/
}
printf("\n");/*每一行後換行*/
}
}
【程序9】
題目:要求輸出國際象棋棋盤.
1.程序分析:用i控制行,j來控制列,根據i+j的和的變化來控制輸出黑方格,還是白方格.
2.程序源代碼:
#include "stdio.h"
main()
{
int i,j;
for(i0;i<8;i++)
{
for(j0;j<8;j++)
if((i+j)%20)
printf("%c%c",219,219);
else
printf(" ");
printf("\n");
}
}
【程序10】
題目:列印樓梯,同時在樓梯上方列印兩個笑臉.
1.程序分析:用i控制行,j來控制列,j根據i的變化來控制輸出黑方格的個數.
2.程序源代碼:
#include "stdio.h"
main()
{
int i,j;
printf("\1\1\n");/*輸出兩個笑臉*/
for(i1;i<11;i++)
{
for(j1;j<i;j++)
printf("%c%c",219,219);
printf("\n");
}
}
【程序11】
題目:古典問題:有一對兔子,從出生後第3個月起每個月都生一對兔子,小兔子長到第三個月
後每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數為多少
1.程序分析: 兔子的規律為數列1,1,2,3,5,8,13,21....
2.程序源代碼:
main()
{
long f1,f2;
int i;
f1f21;
for(i1;i<20;i++)
{ printf("%12ld %12ld",f1,f2);
if(i%20) printf("\n");/*控制輸出,每行四個*/
f1f1+f2; /*前兩個月加起來賦值給第三個月*/
f2f1+f2; /*前兩個月加起來賦值給第三個月*/
}
}
【程序12】
題目:判斷101-200之間有多少個素數,並輸出所有素數.
1.程序分析:判斷素數的方法:用一個數分別去除2到sqrt(這個數),如果能被整除,
則表明此數不是素數,反之是素數.
2.程序源代碼:
#include "math.h"
main()
{
int m,i,k,h0,leap1;
printf("\n");
for(m101;m<200;m++)
{ ksqrt(m+1);
for(i2;i<k;i++)
if(m%i0)
{leap0;break;}
if(leap) {printf("%-4d",m);h++;
if(h%100)
printf("\n");
}
leap1;
}
printf("\nthe total is %d",h);
}