1. 程式人生 > >關於char (*p)[] 和char p[]的問題(轉)(2006-12-26 21:56)

關於char (*p)[] 和char p[]的問題(轉)(2006-12-26 21:56)

char (*p)[]是定義一個指向char型陣列的指標.
char p[]是定義一個數組,p也是指標,只不過是常量.對吧?
#include <stdio.h>
int main()
{
        char (*p)[10] ;
        char a[10];
        p=a;
}
為什麼提示
[[email protected] ~]# cc test.c
test.c: 在函式 ‘main’ 中:
test.c:6: 警告:從不相容的指標型別賦值呢?

你把p=a 改成 p=&a就可以了。
這是c語言迷惑人的地方。很多書都告訴大家陣列名就是陣列的地址,但其實它是的陣列第一個元素的地址,型別是char *。而&a 表示的才是陣列的地址,型別是char (*)[10]。由於陣列的地址在值上面和陣列第一個元素地址的值是相同的,所以大家平時就認為&a和a是一樣的,產生了誤會。
所以,p=a的警告在於你把一個char型的地址賦給了一個char (*)[10]的指標。當然,這樣做的結果沒錯,不過多了個警告。 //在vc7中試了一下,cpp檔案連編譯都過不了,c檔案可以過。明顯c++更嚴格,更妥當。by imjacob
 
 
--------------------------------------------------------------------------------
 
指向陣列的指標 和 指標陣列是不一樣的
指向陣列的指標char (*p)[10]表示p指的是一個數組,//?應該是一個指標。imjacob
p+1與p的差距是sizeof(char [10]),是移動指到另一個數組,這裡sizeof(p)在32位機器上應該是4,指標的長度是4。
指標陣列char *p[10],表示的是一個數組,陣列中每個元素都是指標,這裡sizeof(p)在32位機器上應該是40,=10 * sizeof(char*),這兒是陣列的長度,而不是指標的長度,也說明他是個陣列,跟指向指標的指標(char **p)也是不一樣的
還不明白自己去看書了,不回覆了
 

好像大家說得挺複雜的,這個問題,其實可以歸納為三個問題:
1、p是什麼?
2、a是什麼?
3、&a又是什麼?
先看這個例子:
int *p;
int a[10];
p = a;
這裡,p = a ,其實僅僅是指向了陣列的下標為0的元素,它僅代表一個元素,而不是整個陣列,你不能用指標p來描述整個a[10],除非你做一個迴圈。
好了,把最後一句 p = a改為:
p = &a;
p 僅僅是代表一個元素,而&a是整個陣列的地址(&a實際上是指向陣列a的指標),一個元素是不能指向整個陣列的,因為它們型別不一致,編譯器會警告!!!
(令人疑惑的是:雖然是警告,但又可以編譯執行,這是因為&a使終表示一個地址,如0x0012ff70,而&a[0]也是一個地址,p = &a[0],那當然……,雖然可以執行,但是從型別上來講,這樣是不對的)
說了一大堆和樓主問題不相干的。其實好像已經回答了這個地址,樓主的程式中:
p是一個指標,是一個指向有10元素的陣列的指標,——它已經代表了10個元素,不再代表一個元素了!!!
a,前面已經說了,a是下標為0的元素的地址——它僅代表了&a[0]
大家好像不在一個數量級別上吧?編譯器當然要警告你,當然你也可以強行這麼用,原因如前所述。
所以,要讓大家在一個級別上,很簡單,把最後一句
p = a;
改成
p = &a;
搞定!!!
後記:雖然a[10]中,a和&a,表示的絕對的地址的二進位制數是相同的,比如0x001270FF,但是,它們代表的含義卻不是一樣的!!!
我舉例用了int來代替樓主的char型別,主要是因為char常常讓我們迷惑……之所以迷惑,是因為我們習慣於
char *p;
char a[10];
p=a;
/*以下把p看成一個字串來用*/
事實上,C是沒有字串的型別的,p 之所以能看成字串,因為p指向了第一個元素,我們可以使用它,直至'\0'
Over!
不對之處還請諒解!
 

兩個指標級別都不一致,一個是char (*)[10], 一個是char [10],當然要警告你一下
char [10] 是陣列 a 的定義型別,是陣列型別,而不是指標型別。陣列可以轉換為指標,所以一個數組到底是作為陣列型別還是指標型別使用取決於它所處的上下文環境。程式中的 p = a; 中 a 作為指標使用,此時它的型別是 char*。
>>(char p[] 中,)你這個p怎麼能++的哦,這個p就是個常量,不是左值,不能對其進行賦值什麼的操作
>> a是指標常量,不能作為左值,當然也是不能自增的了..
首先可以肯定的是:樓主程式中的陣列 a 是一個非靜態陣列,所以 a 不是一個常量。
經常看到上面的這種錯誤的觀點,即把改變陣列名 a 的操作(如對其賦值、自加等)是非法的原因歸結於“陣列名是常量”。我在下面的帖子中對此進行了澄清:
http://bbs.chinaunix.net/viewthr ... p;extra=&page=2
按照標準的說法,陣列名 a 不能被改變是因為陣列物件是一個“不能被改變的左值”。這句話表達了兩個意思:一是陣列物件是一個左值,二是不存在陣列型別的賦值、自加、自減等操作。另外,陣列物件 a 作為指標使用的時候,你可以說它是一個常量指標(這總是正確的),然而能否說成是一個指標常量(即地址常量)就又另當別論了(具體參見上面給出的帖子中的內容)。
>> 不過a裡面存的不已經是陣列第零個元素的地址,怎麼還能&取址呢?
因為這個地址值是“轉換”而來的,而不是存放在變數 a 中,這是陣列型別一個比較特殊的地方。另外,能對陣列 a 進行取址運算是因為 a 表示陣列物件的時候是一個左值。
>> 難道&a和a內容一樣,差別在於型別變了,一個是單個元素的指標,一個是陣列的指標了麼?
&a 和作為指標使用的 a 這兩個表示式都只有“值”的概念,不代表任何物件,所以沒有你所認為的“內容”。它們的值僅僅是在數值上相等(因為指向位置相同),然而指標型別不同:前者是 char(*)[10],後者是 char*。
 
#include <stdio.h>
int main()
{
        char (*p)[10] ;
        char a[10];
        p=a; // First of all, "a" means &a[0],  p should be assigned with the address of an array, not the address of the array element.
        You should write as : p = &a;
}

/*----------------------------
看後寫出如下程式,正確得到結果
----------------------------*/
#include <stdio.h>
#include <string.h>

int main()

 
        char (*p)[10] ;  //長度有問題,10改成12,by imjacob
        char a[10];           //長度有問題,10改成12,by imjacob

       
        strcpy(a,"hello,world");
       
        p=&a;
              
        cout<<"p = "<<*p<<"the second char in p is "<<(*p)[1]<<endl;   
   
        return 0;
       
}
本文來自:我愛研發網(52RD.com) - R&D大本營
詳細出處:http://www.52rd.com/Blog/Detail_RD.Blog_imjacob_5648.html