最近老感覺自己的身體一天不如一天,老是丟三落四的, 哎,歲月啊..................
在此給還在被中國教育的童鞋們一個建議.............在學校的時候還是小玩玩遊戲,小談談一些海闊天空的事,當你工作後,你會發現你
不但沒有時間這個本錢了, 同時連身體這個本錢也沒有了..........
上次說了一些有意思的面試題, 今天我們結著看看一些關於指標和sizeof的面試題:
下面是我看到的一些面試題
5、簡述
char * const p;
char const *p;
const char *p;
之間的區別。
首先討論:
char * const p; 這裡可以知道const修飾是指標變數p; 因此指標p的指向不能改變,這樣的變數
定義必須首先初始化,否則將不能編譯通過。但是p指向的變數的儲存內容可以改變。
Exp:
char chTest1;
char chTest2;
char * const p=&chTest1;
// p=&chTest2; 這個地方是錯誤的,不能這樣賦值
*p=‘c’;
chTest1=‘b’;
接下來討論:
char const *p; 這裡可以知道const修飾的是*p; 因此可以知道不能通過*p指向來改變變數的值; 但是
指標p的指向可以改變,而且可以通過原變數進行改變值。
Exp:
char chTest1;
char chTest2;
char const *p=&chTest1;
p=&chTest2;
chTest=‘a’;
這裡可以知道: 1)p的指向可以改變
2)不能通過*p= 某個值進行賦值
3)指標指向的變數的值自己可以改變。
最後討論:
const char *p=&chTest1; 這裡可以知道const修飾的是*p; 因此這個與char const *p;具有相同的效果。
Exp:
char chTest1;
char chTest2;
const char *p=&chTest1;
p=&chTest2;
chTest1='a';
// *p='a'; 這個地方錯誤, 不能這樣修改值。
總結:
修飾符僅對其修飾的對象起作用,對別的變數不起作用。
6、以下代碼中的兩個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;
Exp:
這個問題的考察點是sizeof的用法。那麼我們應該如何看待這個問題呢?
1、這裡首先我們需要知道的是sizeof 是個運算子, 它具有運算的優先順序別, 那麼sizeof運算的優先順序在什麼地方呢?
可以查看運算子優先順序的定義: sizeof 的優先順序和 *p(P為指標)、&p(變數,取地址)的優先順序一樣, 排在優先順序的第二位。
2、其次要明白sizeof關鍵字的作用
sizeof 關鍵字返回的是運算元在記憶體中佔用的位元組數。
這裡要看sizeof操作符的操作對象:
1) 類型關鍵字
sizeof(int): 這個取決系統的定義, 當在32位機器上時; sizeof int == 4
而在16位機器上時, sizeof int == 2
2) 變數
int iTest;
sizeof iTest; 這樣返回的是這種變數類型在記憶體中所佔用的空間。
即:
sizeof iTest == sizeof int;
3) 字串字面值
sizeof "abcd";
那麼返回的是:字串在記憶體空進中佔用的位元組數。 這裡我們知道"abcd"在記憶體中佔用的是5個位元組,那麼很顯然有
sizeof "abcd"==5;
4) 數組
這裡有點難度
char chTest[5];
sizeof(chTest)==5; //這裡可以知道chTest數組有5個元素,並且每個元素佔用一個位元組,因此sizeof(chTest)==5;
那麼如果我們這樣定義呢?
int iTest[5];
sizeof(iTest)= ? // 答案是10 , 因為有5個元素,每個元素佔兩個位元組,所以佔用10個位元組的空間。
二維數組呢?
char chTest[10][20];
sizeof(chTest)= ? //200
既然sizeof(chTest)==200; 那麼sizeof(chTest[10])= ? 答案是 20 .
又如:
int iTest[10][20];
sizeof(iTest)= ? // 400
同樣 sizeof(iTest[10])= ? 答案是 20
通過這裡我們得出結論:
對於sizeof運算元組的時候要分兩種情況:
a、 一維數組
sizeof(數組名) 返回的是 數組元素個數 * 每個元素佔用的位元組數
sizeof(數組名[n]) 返回的是: 數群組類型定義的單個變數所佔用的位元組數
即:
int iTest[4];
則
sizeof(iTest)=8;
sizeof[iTest[1]]=2; //這裡假設 sizeof[int]=2
b、 多維陣列
sizeof(數組名) 返回的是:一維的長度*二維的長度*....* 每個元素佔用的位元組數
sizeof(數組名[n]) 返回的是:其後面各位長度的乘積* 每個元素佔用的位元組數,
這樣必須保證sizeof的運算元沒有取到最後一維。
即: int iTest[2][3][4];
sizeof(iTest[2][3])= 4*sizeof[int]=8; //這裡假設用的是16位系統
c) 多維陣列
sizeof(陣列變數定義式);
即:
int iTest[2][3][4][5];
sizeof(iTest[2][3][4][5])= ?
這裡返回的是 數組的維數 就是 4 。
5、傳遞的是指標的時候
如果操作的是指標那麼情形又如何呢?
這裡也分兩種情形:
1)當運算元是指標本身的時候
Exp:
int *iTest;
那麼
sizeof(iTest) = ? //這裡有一個規則,當sizeof操作變數的時候,返回的是變數本身的儲存長度, 因此
//如果在16位的系統中, 這裡返回2; 而在32位系統中返回的是4;
2)當運算元有* 取值間接運算子號時
Exp:
int *iTest;
那麼
sizeof(*iTest) = ? // 這裡返回的是 2, 其實返回的是sizeof(int)的長度; 即返回的是其指向的
//變數類型的 所佔用的空間
可以用:
float *fTest;
sizeof(*fTest)= ? // 這裡返回的值是 4
sizeof(fTest)= ? // 取決於系統 16位的系統返回 2, 32位系統返回 4, 64位系統返回8 即地址匯流排的寬度。
現在回到我們的問題:
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;
1、首先確定sizeof的文法問題:
for( size_t i=0; i <sizeof(str)/sizeof(str[0]); ++i ) //文法沒有問題
sizeof(str)/sizeof(str[0]) //文法也沒有問題
2、接著確定邏輯有沒有問題
我們先看: sizeof(str[0])分析可知str[0]是個char的變數 , 因此佔用一個位元組;
再看:
sizeof(str); 這裡str是一維數組同時是數組名, 因此返回的是數組的長度,
貌似可以實現. 但是我們忽略了一個問題:
數組當做實參傳遞的時候,最後一個 ‘\0’是不會傳遞的。
3、 既然不能傳遞那麼我們啟動並執行時候是否可以得到正確結果呢
答案是肯定的。
這個可以在VC6.0中用下列代碼測試:
Exp:
/*
* test the sizeof key word
*
*/
#include <stdio.h>
#include <conio.h>
void UpperCase( char str[] )
{ int i;
printf("%d,%d",sizeof(str),sizeof(str[0]));
for(i=0; i< sizeof(str)/sizeof(str[0]) ;++i )
if( 'a' <=str[i] && str[i] <='z' )
str[i] -= ('a'-'A' );
}
int main(int argc,char *argv[])
{
char chTest[]="abcd";
printf("%d\n",sizeof(chTest));
UpperCase(chTest);
puts(chTest); // 因為我們知道chTest[4]='\0'. 所以雖然沒有傳遞,但是還是可以實現轉換的功能
getch();
}
通過這個例子可以看出來, 有些時候確實不是我們想的那樣,