之前就知道數組名和指針不同,因為運算符sizeof對數組名和指向數組的指針的運算結果是不同的---sizeof數組名得到的是數組空間的大小,而sizeof指向數組的指針獲得的是指針自身占據空間大小。而如果是對指針進行解引用,即對象是指針指向的,那麼sizeof得到的是這個對象的大小。
舉例:
char aszFoo_Name[4];
char *pcFoo_Name = aszFoo_Name;
sizeof(aszFoo_Name) = 4;
sizeof(pcFoo_Name) = 8;
sizeof(*pcFoo_Name) = 1;
今天恰好看到關于linux(注意可移植性)裡面對于0數量成員的數組的一些解釋,舉例:
typedef struct tagFoo_xxx
{
char cT1;
char acT2[0];
}Foo_xxx;
acT2就是我說的這種成員數量為0的數組,sizeof(Foo_xxx)得到的大小是1,可以驗證acT2這種數組是不占空間的,引用别人部落格的一段話:
char a[1]裡面的a和char *b的b相同嗎?《 Programming Abstractions in C》(Roberts,
E. S.,機械工業出版社,2004.6)82頁裡面說:“arr is defined to be identical to
&arr[0]”。也就是說,char a[1]裡面的a實際是一個常量,等于&a[0]。而char *b是有一個實實在在的指針變量b存在。
是以,a=b是不允許的,而b=a是允許的。
上面這種東西的用法大緻如下,也是從别人的部落格搞來的:
#include <stdlib.h> #include <string.h> struct line { int length; char contents[0]; // C99的玩法是:char contents[]; 沒有指定數組長度 }; int main(){ int this_length=10; struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length); thisline->length = this_length; memset(thisline->contents, 'a', this_length); return 0; }
上面這段代碼的意思是:我想配置設定一個不定長的數組,于是我有一個結構體,其中有兩個成員,一個是
length,代表數組的長度,一個是contents,代碼數組的内容。後面代碼裡的this_length(長度是10)代表是我想配置設定的資料的長度。(這看上去是不是像一個C++的類?)這種玩法英文叫:FlexibleArray,中文翻譯叫:柔性數組。
需要注意的是後面根的緩沖區不能自己釋放,是以要手動釋放,防止記憶體洩露。。。
我感覺可以結合一下了解下數組名是什麼東西。
而且對數組名取位址和數組名的值是相同的,那麼 數組名指向的是首個元素的位址,數組名取位址指向的是數組的位址,是以這兩者的值是相同的。結合數組指針來了解一下:
char acTest[3]={1,2,3};
char (*pacTest1)[3]=&acTest;
char *pacTest2= acTest;
printf("%d",acTest);
printf("%d",&acTest);
printf("%d",*acTest);
printf("%d",*(&acTest));
數組指針pacTest1是指向數組的一個位址,是以将數組名的取位址的值賦給它,同樣char指針代表指向一個char的位址,這裡用數組名指派。而四個printf的輸出結果,一二四是相同的,都是同一位址,而第三輸出為1.這樣就可以佐證上面的說法是正确的。
那麼二維數組又是怎樣的呢:
char acTest[2][3]={1,2,3,4,5,6};
char (*pacTest1)[3]=acTest;
char (*pacTest2)[2][3]=&acTest;
printf("%d",acTest);
printf("%d",&acTest);
printf("%d",*acTest);
printf("%d",*(&acTest));
這次四個表達式的值是相同的。二維數組可分解為多個一維數組,即以一維數組為成員,如二維數組acTest可分解為擁有三個成員:acTest[0],acTest[1],acTest[2]的數組,是以數組名直接指向的是其成員:一維數組,而對其取位址得到的才是二維數組位址,這和上面的結論相同。那麼四個值相同,acTest指向一維數組acTest[0],其為一維數組的位址。&acTest指向二維數組本身。*acTest即acTest[0],也就是第一個一維數組的第一個成員的位址。最後一個與第一個相同。
數組名取位址的類型是一個數組指針類型,但它不是數組指針;而數組名的類型為這個數組的成員的類型的指針的類型,它同樣不是指針(好繞。。)因為指針的sizeof都是指針自身空間的大小~~~這個也可以結合數組下标通路的文法糖來了解,a[i]=*(a+i),a[i][j]=*(a+i)[j]=*(*(a+i)+j)是以a也必定是指向其成員的指針的類型。這裡gdb裡看一下對應的類型:
char a[2][3]={1,2,3,4,5,6};
(gdb) ptype &&a
A syntax error in expression,near '&&a'.
(gdb) ptype &a
char (*)[2][3]
(gdb) ptype a
char [2][3]
(gdb) ptype &a[0]
char (*)[3]
(gdb) ptype &a[0][0]
char *
&a是二維數組指針類型,a是一維數組指針類型,&a[0]是一維數組指針類型,&a[0][0]是指向基本數組元素的指針類型。還有一點,在第一行取值的時候,對數組名取兩次位址,顯示原型錯誤,這應該是代表數組名取兩次位址沒有意義,是以不給列印。假設有一個n維數組,a[b1][b2]…[bn],其中bi為第i維數組的長度(i=1,2,…n),那麼元素a[j1][j2]…[jn]的數值為一遞歸函數:
f(n)=*(f(n-1)+jn)
其中f(0)=a,n>=1
或者另一中方式, a[j1][j2]…[jn]的位置為:
LOC(a[j1][j2]...[jn]) = LOC(a)+(b2*b3*...bn*j1+b3*b4*...bn*j2+...+jn)L
其中LOC(x)代表x的位置,L為數組基本元素的長度
今天又看到兩種模拟二維數組的方法,也可以拿過來了解一下:
一、利用一個二級指針來實作
#include<stdio.h>
#include<malloc.h>
int main()
{
//5行2列的數組
int **p = (int **)malloc(sizeof(int *) * 5);
for (int i = 0; i < 5; ++i)
{
p[i] = (int *)malloc(sizeof(int) * 2);
}
for (int i = 0; i < 5; ++i)
{
for (int j = 0; j < 2; ++j)
{
//輸出數組每個元素位址
printf("%p\n", &p[i][j]);
}
}
for (int i = 0; i < 5; ++i)
free(p[i]);
free(p);
return 0;
}
二級指針指向了一塊五個int的空間,每個int空間裡面儲存了兩個Int空間的位址。
當使用文法糖通路時,p[i][j]先通過i定位到第幾個int空間,p[i]就是一個Int,而後j則可以在指向的空間内移動,每次移動sizeof(int)大小。
二、利用數組指針來實作
#include<stdio.h>
#include<malloc.h>
int main()
{
//申請一個5行2列的整型數組
int(*p)[2] = (int(*)[2])malloc(sizeof(int) * 5 * 2);
for (int i = 0; i < 5; ++i)
{
for (int j = 0; j < 2; ++j)
{
//輸出數組每個元素位址
printf("%p\n", &p[i][j]);
}
}
free(p);
return 0;
一維數組指針是一個指向一維數組的指針,當p+i,每次移動整個數組所占空間大小,p[i]即相當于一維數組位址,也是指向第一個成員的位址,而j可以确定在數組中成員的位置