PCDVD數位科技討論區

PCDVD數位科技討論區 (https://www.pcdvd.com.tw/index.php)
-   疑難雜症區 (https://www.pcdvd.com.tw/forumdisplay.php?f=34)
-   -   VC++的幾個問題part05.. (https://www.pcdvd.com.tw/showthread.php?t=257830)

SGI 2003-10-14 10:07 AM

VC++的幾個問題part05..
 
好久沒來發問囉!!
但這並不代表我偷懶唷~!
只是有關於生計問題的事要忙
所以只好把學習進度延一下了
仍然請諸位高手不吝賜教囉!!

1)假設A為一個陣列
為何cout <<(sizeof A)/(sizeofA[0])
就可以表示陣列中有多少個元素呢?

2)對指標的基本概念我大概懂了
但為何指標陣列和一般的字元陣列相比,占用的記憶體
會比較小,而且當字串長短變化較大時,指標陣列可節
省更多空間呢?

先感謝大家的寶貴意見囉~!

Chief_WU 2003-10-14 10:25 AM

1. 假設
int x[5];

cout << sizeof(x[0]) << endl; // output is 4 because size of an integer is 4 bytes
cout << sizeof(x) << end; // output is 4 * 5 = 20 bytes. 4 bytes per each int element and total has 5 elements

SO

cout << sizeof(x) / sizeof(x[0]) << endl; //prints 5 (elements) because of 20 / 4

2. 不會解釋

harrisonlin 2003-10-14 12:07 PM

回覆: VC++的幾個問題part05..
 
好久不見啦~

1.陣列的長度 / 個別元素的長度,不就是陣列的元素的個數了嗎?

2. "指標陣列和一般的字元陣列相比,占用的記憶體會比較小"...我猜你大概是指「字串(char *)為什麼比字元陣列節省記憶體」吧(不是指標陣列)?!

如果要處理的字串長度變化大時(例如每個人的通訊地址),若是使用字元陣列,你必需要宣告一個「足夠大」的陣列,以應付各種可能(也許有人連太陽系地球都寫進去),那麼不但這個長度不好拿捏,且若是填入的字串很短,那麼豈不浪費剩餘的空間?簡單地說,就是「彈性差」,但是「效率高」,因為它在編譯期就知道要配置多大的記憶體空間了(好比你出去玩之前就先跟飯店訂好房間,那麼你一到目的地後就可以馬上下榻;若是你到了飯店再問有沒有空房,櫃臺再去查電腦,然後再告訴你房間號碼,這樣自然是比較慢的了)!

反之,若是使用字串,那就會在程式被執行時才去尋找一個可用的、連續的記憶體空間來放置這個字串,所以它的「彈性高」,但「效率差」(就好比你出發去玩之前不先找飯店訂房間,到了目的地之後再去找;這間飯店沒有房了再找另一間,直到找到為止)!這裡的彈性,指的就是「浪費記憶體的程度」囉!

SGI 2003-10-14 05:29 PM

回覆: 回覆: VC++的幾個問題part05..
 
引用:
Originally posted by harrisonlin
好久不見啦~

1.陣列的長度 / 個別元素的長度,不就是陣列的元素的個數了嗎?

2. "指標陣列和一般的字元陣列相比,占用的記憶體會比較小"...我猜你大概是指「字串(char *)為什麼比字元陣列節省記憶體」吧(不是指標陣列)?!

如果要處理的字串長度變化大時(例如每個人的通訊地址),若是使用字元陣列,你必需要宣告一個「足夠大」的陣列,以應付各種可能(也許有人連太陽系地球都寫進去),那麼不但這個長度不好拿捏,且若是填入的字串很短,那麼豈不浪費剩餘的空間?簡單地說,就是「彈性差」,但是「效率高」,因為它在編譯期就知道要配置多大的記憶體空間了(好比你出去玩之前就先跟飯店訂好房間,那麼你一到目的地後就可以馬上下榻;若是你到了飯店再問有沒有空房,櫃臺再去查電腦,然後再告訴你房間號碼,這樣自然是比較慢的了)!

反之,若是使用字串,那就會在程式被執行時才去尋找一個可用的、連續的記憶體空間來放置這個字串,所以它的「彈性高」,但「效率差」(就好比你出發去玩之前不先找飯店訂房間,到了目的地之後再去找;這間飯店沒有房了再找另一間,直到找到為止)!這裡的彈性,指的就是「浪費記憶體的程度」囉!

------------------------------------------------------------------
真的好久不見囉~又要麻煩大大線上教學了

1)容小弟囉嗦一點,我舉個例子好了

char* PP[]={ "Merry Christmas",
"Happy Birthday",
"Happy New Year"
};
int num=(sizeofPP)/(sizeofPP[0]);

在以上敘述中小弟有幾個問題:
(a)在以上陣列中,是否佔用了3個不同記憶體位置來儲存這3個
不同的字串?
(b)PP[0]是否單指"Merry Christmas"這個字串?,如果是,
為何 (sizeofPP)/(sizeofPP[0]) 就可代表整列字串的元素個數?
這3個字串不是都不一樣長,佔用的位元數也都不一樣嗎?


2)嗯...我有一點被搞混了
大大你所謂的字串陣列是不是指像這樣

char* PP[]={ "Merry Christmas",
"Happy Birthday",
"Happy New Year"
};
這不是"指標型態的字串陣列"嗎?

而字元陣列是不是像這樣

const int MAX=100;
char QQ[MAX]="Hello!";

但是不是所有字串陣列都會用指標表示
所以大大你的意思是說"宣告為指標型態的字串陣列會比字
元陣列來得有彈性是嗎"?

最近一直在指標陣列這邊繞啊繞的
感覺越繞越迷糊....

harrisonlin 2003-10-14 06:16 PM

指標是C/C++難學的一環,也是它強大的一環。一開始會搞不清楚是很正常的,唯有多練多思考囉!

1)其實 char* PP[] 並非真的存入"3個字串",而是存入"3個字元指標(就是指字串)",所以PP[0]也是一個指標而已,而不是真的一個字串。用一個指標來代表字串的原因在於,C/C++中並沒有內建"字串"這種資料型態(C++的標準類別庫中有,但仍然不是"內建"資料型態),所以用指向字元的指標來代表一個字串的起始位址,從這個位址起到第一個'\0'為止,視為一個字串。我就延伸你的例子來說明:

char* PP[]={ "Merry Christmas",
"Happy Birthday",
"Happy New Year"
};
int num=(sizeof(PP))/(sizeof(PP[0]));

cout << "sizeof(PP) : " << sizeof(PP) << endl;
cout << "sizeof(PP[0]) : " << sizeof(PP[0]) << endl;
cout << "Element count : " << num << endl;

執行之後,你會發現 sizeof(PP) 是 12, sizeof(PP[0]) 是 4,而元素數量是 3。關鍵在 sizeof(PP[0]) 上,這裡得到"在這個系統中指標所佔的記憶體大小(別忘了,指標也是一種資料型態,也佔記憶體,它所代表的值就是某個記憶體位址)",在windows & linux 上都是 4 個 bytes(我不清楚這是因 OS 還是硬體架構而異),所以這個「指標陣列」一共 12 個 bytes, 所以算下來可以得知有 3 個指標,也就是 3 個字串。

2)
char* PP[]={ "Merry Christmas",
"Happy Birthday",
"Happy New Year"};
這個就是一個字串陣列呀!和上面提到的一樣,C/C++沒有內建字串資料型態,所以用"指向字元的指標"來代表一個字串的開頭,再以第一個'\0'作為結尾;所以與其說這是一個"指標型態的字串陣列",不如說是"C風格的字串陣列"!因為在C++中,使用"String"這種class 來替代 char* 是比較好的解決方案。至於"彈性"的問題,使用 char* 的彈性是比 char[size] 來得高,因為這個 size 在編譯時就要決定了;但是"彈性"的需求也是視狀況而定,若是要處理的資料長度變動不大,使用 char[size] 會是比較有效率的作法(因為OS尋找可用的記憶體空間也是需要花費一些時的)。

SGI 2003-10-15 10:13 AM

引用:
Originally posted by harrisonlin

1)其實 char* PP[] 並非真的存入"3個字串",而是存入"3個字元指標(就是指字串)",所以PP[0]也是一個指標而已,而不是真的一個字串。用一個指標來代表字串的原因在於,C/C++中並沒有內建"字串"這種資料型態(C++的標準類別庫中有,但仍然不是"內建"資料型態),所以用指向字元的指標來代表一個字串的起始位址,從這個位址起到第一個'\0'為止,視為一個字串。我就延伸你的例子來說明:

char* PP[]={ "Merry Christmas",
"Happy Birthday",
"Happy New Year"
};
int num=(sizeof(PP))/(sizeof(PP[0]));

cout << "sizeof(PP) : " << sizeof(PP) << endl;
cout << "sizeof(PP[0]) : " << sizeof(PP[0]) << endl;
cout << "Element count : " << num << endl;

執行之後,你會發現 sizeof(PP) 是 12, sizeof(PP[0]) 是 4,而元素數量是 3。關鍵在 sizeof(PP[0]) 上,這裡得到"在這個系統中指標所佔的記憶體大小(別忘了,指標也是一種資料型態,也佔記憶體,它所代表的值就是某個記憶體位址)",在windows & linux 上都是 4 個 bytes(我不清楚這是因 OS 還是硬體架構而異),所以這個「指標陣列」一共 12 個 bytes, 所以算下來可以得知有 3 個指標,也就是 3 個字串。


------------------------------------------------------------------
嗯...稍微有點懂,但好像還差那麼一點
請容小弟再發個問
就以相同的例子

1)大大您說 char* PP[] 並非真的存入"3個字串",
那麼是否是存入"3個記憶體儲存位置,然後這3個位置再分別指向
這3個不同字串呢?"

2)PP[0]也是一個指標,那麼它是否指向"Merry Christmas"這個字串?
如果不是,那pp[0]到底是什麼? 那有pp[1],pp[2]這玩意嗎?

3)這陣列佔用了12 byte的"容量",這"容量"可以自己算嗎?

4)指標是記憶體的儲存位置,那麼不管它指向的內容(也許是幾個字母,
數字甚至是冗長的字串)為何,都是佔用4byte嗎?

這些對小弟來說還是蠻不了解的,還望大大多多海涵,能再給小弟我
一些寶貴的意見,感謝您唷

harrisonlin 2003-10-15 10:43 AM

呵呵,正所謂「教學相長」,幫你釋疑的同時,我也可以趁此驗證我的觀念有無漏洞,有問題的話別客氣,提出來一起討論囉!

1) char* PP[] 的確只是存入 3 個指向字串的指標,從宣告上就可以看得出來了!這 3 個指標存著 3 個記憶體位址,指向字串。

2)既是字串(或說字元指標)的陣列,裡頭儲存的東西自然就不會是別的囉! PP[0] 的確是指向某個字串的指標,這個陣列中的其它元素亦是如此。

3)C/C++所提供的基本陣列型態,並沒有記錄本身長度的功能(C++的標準類別庫所提供的陣列物件似乎是有的...)。所以一個陣列的長度,就要靠某個變數來記錄了!但是字串不需要刻意去記這個長度,因為字串一定以'\0'結尾,所以只需去判斷這個結束字元,就可以讀取整個完整字串了。

4)沒錯,指標所記錄的資料就是某個記憶體"位址",無論這個指標所指向的資料為何,皆是如此。

SGI 2003-10-15 04:28 PM

引用:
Originally posted by harrisonlin


4)沒錯,指標所記錄的資料就是某個記憶體"位址",無論這個指標所指向的資料為何,皆是如此。

------------------------------------------------------------------
感謝大大這麼詳細的說明
小弟聽大大一席話
雖不敢說已豁然開朗,打通任督二脈
但至少已無墜五里霧中的感覺
但關於第四點,小弟仍有不解之處:

那麼,依這個例子來看,這個"位址"所占用的位元數
就是4 byte囉?那不管此位置指向的內容為幾百字的字串
或是只有一個單字,容量都是4byte?如果是的話,為什麼不管
位址指向的內容再怎麼變都是4byte呢?
還是我把"位址"跟"位元數"弄混了呢?

請大大再次指導囉~

harrisonlin 2003-10-15 05:59 PM

你是否對於"指標指向的資料長度不一,卻又同樣只佔 4 bytes"感到疑惑呢?

其實詳細地說,指標記錄著某個"位址",而這個"位址"只是代表著某一"段"記憶體的開頭,裡頭存放著某些資料,舉例來說 :

int a = 10;
int *p = &a;

假設目前 a 在記憶體中的位址是 1000,那麼 p 目前的值就是 1000。因為一個在32 位元機器的 int 上是 4 bytes,所以接下來的1001, 1002, 1003就是這個變數 a 所佔用的空間,裡頭存放著 10, 指標 p 只是指向 1000 這個位址。當程式透過 p 來讀取變數 a 的值時,系統會讀取從 p 所指向的位址開始之後的 4 bytes (1000, 1001, 1002, 1003)的資料,並把它傳給程式。指標就像是一個標籤,記著記憶體中的某個位址,而這個位址之後多少 bytes 是屬於這個資料的,就看指標所指向的型態了:若是 int 指標,那麼指向位址後的 4 bytes(或 2 bytes,在 16 位元的機器上)就是這一個 int 的值;若是 float 指標,那麼指向位址後的 4 bytes 就是一個 float 的值。指向char 的指標就比較不同,從"指標指向的位址起"至"第一個'\0'出現的位址"止,是一個字串的值。

這樣解釋明白了嗎?;)

phonxe 2003-10-15 08:32 PM

有時候pointer跟array是可以混著用,
compiler會自動幫你處理好,如:
char p1[]="01234";
char* p2="01234";

cout<< p1 << " " << p2 <<endl;
cout<< p1[0] << " " << p2[0] <<endl;
前後都會有相同的輸出 :
01234 01234
0 0

cout<< sizeof(p1) << " " << sizeof(p2) <<endl;
但這會輸出什麼呢?
答案是:
6 4

sizeof(p1) 等於 6:
因為 p1 是個array,內容為 "01234" + '\0' 共六個 byte

而 sizeof(p2) 等於 4:
因為 p2 是個 pointer ,在 32bits 的電腦架構下就是 32bits==4bytes
至於 p2 指到的內容 "01234\0" 則是用另外的記憶體空間來儲存


所有的時間均為GMT +8。 現在的時間是03:16 AM.

vBulletin Version 3.0.1
powered_by_vbulletin 2026。