有日子沒有學習C語言了, 前些天在看windows程序設計時, 按照win的體系結構,在VC 6裡面找到
下面一段代碼,發現自己的C語言功底實在是差之又差。代碼為我看到的C代碼,至目前為止,還只能理解個大概;
估計要慢慢體會了。
View Code
DECLARE_HANDLE(HDC);#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
上面的代碼等我理解後再和大家分享吧, 下面說說這一次的C語言面試題。
8、找錯題
找出下面幾個函數的錯誤:
試題1:
void test1()
{
char string[10];
char* str1 = "0123456789";
strcpy( string, str1 );
}
/*
這個題目咋一看,沒有任何錯誤, 給strcpy()函數傳遞的兩個實參參數類型均能滿足要求。
但是細心一看我們會發現這個函數存在越界問題,"0123456789"這個字符串
的長度為 strlen("0123456789") + 1 = 11 , 而很顯然string[10],不可能存儲這麼大的空間
通常在使用strcpy函數時一定要考慮源串、和目的串的大小問題。
*/
函數改成下面的形式可能會健壯一些:
int StrCpy(const char *source; char dest[])
{
if( NULL==source || NULL == dest || ( strlen(dest) < strlen(source) ) )
return 1; // 返回值=1 表示復制失敗
else
strcpy(dest,source);
return 0; //返回值=0 表示復制成功
}
試題2::
void test2()
{
char string[10], str1[10];
int i;
for(i=0; i<10; i++)
{
str1 = 'a';
}
strcpy( string, str1 );
}
/*
這個題目考查了兩個問題:
1、 數組的首地址是常量,不可以作為左值, 即str1是一個常量,
它代表整個數組的首地址。
2、 第二數組的引用需要用下標,除了初始化時可以int iArray[10]={1,2}
這樣賦值外,在其他地方不可以批量給數組元素賦值。
3、 同時strcpy復制函數是針對具有'\0'的字符類型變量,因此這個函數賦
值同樣存在賦值越界的情況。
*/
改成下面的方式估計會健壯一些:
void test2( )
{
char string[10],
str1[10] ;
for(int i=0; i<10; i++)
str1[i] = 'a';
str[9]='\0';
strcpy(string , str1);
}
試題3:
void test3(char* str1)
{
char string[10];
if( strlen( str1 ) <= 10 )
{
strcpy( string, str1 );
}
}
//試題3同樣存在越界的可能性。如果strlen(str1)=10, 則實際上str1占用的空間是11個。
//strlen函數返回的長度沒有計算末尾'\0'字符。 因此需要注意。
改為下面的方式可能會更健壯:
void test3(char* str1)
{
char string[10];
if( strlen( str1 ) < 10 && NULL != str1 )
strcpy( string, str1 );
}
試題4:
void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory( str );
strcpy( str, "hello world" );
printf( str );
}
/*
首先這個題目存在內存洩露的問題和指針指向空地址問題
說說這個題目的存在的幾個問題:
1、 在GetMemory函數裡面, 沒有對malloc函數返回值進行測試
if(NULL==p)
2、 在函數裡面沒有對指針p進行釋放
free(p);
3、這裡會有一個問題,在C語言中默認時按值傳遞的, 不是按照地址傳遞的。
在程序裡面不能改變str的指向。
GetMemory(str);不能改變str的指向。
函數原型為:
void GetMemory(char *p); 定義的就是一個指針類型的參數。
4、在函數內部不能改變傳值參數的值
*/
/*****************
malloc函數的實質體現在,它有一個將可用的內存塊連接為一個長長的列表的所謂空閒鏈表。調用malloc函數時,
它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然後,將該內存塊一分為二(一塊的大小與用戶請求
的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果
有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閒鏈上。到最後,空閒鏈會被切成很多
的小內存片段,如果這時用戶申請一個大的內存片段,那麼空閒鏈上可能沒有可以滿足用戶要求的片段了。於是,
malloc函數請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閒塊合並成較大
的內存塊。如果無法獲得符合要求的內存塊,malloc函數會返回NULL指針,因此在調用malloc動態申請內存塊時,一定要
進行返回值的判斷。
**************/
改成下面形式可能更健壯一些:
Void GetMemory(char **p)
{
char *temp;
if(NULL != (temp=(char *)malloc(1000)))
*p=temp;
free(temp);
}
試題5:
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
}
/* 其實怎麼說呢這個題目的理解比上面一個題目來對簡單, 但是通過這個題目和上面
的題目需要知道一個事實:
那就是函數內部聲明的局部變量(static類型的除外,當然還有register的除外),這裡指的
是auto類型的變量, 其內存空間是在系統為應用程序開辟的棧裡面申請。
而malloc函數申請的空間則是從系統為應用程序開辟的堆裡面申請。堆裡面申請的不會自動釋放,
而棧裡面申請的會隨著函數聲明周期的結束而自動釋放。
這個題目的錯誤之處在於沒有理解局部變量的生命周期。
*/
改成下面的形式可能會更健壯:
char *getmemory(void)
{
char *p=NULL;
if(NULL !=(p=(char *)malloc(strlen("hello word")+1))
return p;
}
試題6:
void GetMemory( char **p, int num )
{
*p = (char *) malloc( num );
}
void Test( void )
{
char *str = NULL;
GetMemory( &str, 100 );
strcpy( str, "hello" );
printf( str );
}
/*
這個題目在第四個題目已經實現和論述,不再論述
指的一提的是:
傳遞&str值,並不能改變str的指向。
*/
試題7:
void Test( void )
{
char *str = (char *) malloc( 100 );
strcpy( str, "hello" );
free( str );
... //省略的其它語句
}
/*
這個題目比上面的更加簡單, 它的問題就是沒有對malloc函數的返回情況進行
檢測,
如果 NULL=(char *)malloc(NUM) 那麼strcpy函數將不會成功執行,
*/
鑒於本人是個計算機菜鳥, 目前連基本的兼容dos命令都不會, 同時還是個C語言的菜鳥
上面的類容說的不當的地方,歡迎各位彎腰找板磚......................
嘻嘻..............................