1.一维数组转换指针求 sizeof
int a[] = {1, 2, 3, 4}; //四个元素的一维数组
以下严格按照一行代码,再加一行解释的格式来书写
printf ("%d", sizeof(a)); //16
① szieof (a),a为数组名,此时取整个数组的长度,四个元素,每个元素占四个字节。
printf ("%d", sizeof(a + 0)); //4
② szieof (a + 0),此时数组名 + - 数字(a + 1或 a - 1)就转换为指针,此处int型指针的长度为 4
printf ("%d\n", sizeof(*a)); //4
③ sizeof (*a), 此时 *a ,对数组名解引用,转换为指向首元素的指针相当于a[0], 即数字 1 ,int型长度为4
printf ("%d\n", sizeof(a + 1)); //4
④ 此时sizeof(a + 1)和上面sizeof(a + 0)一样,为 int 型指针
printf ("%d\n", sizeof(a[1])); //4
⑤ a[1] 指向 数字 2,整型取sizeof 长度为 4
printf ("%d\n", sizeof(&a)); //4
⑥ 数组名取地址(&a)为整个数组a的地址, 转换为数组指针,指针类型长度为4
printf ("%d\n", sizeof(*&a)); //16
⑦ &a 为指向整个数组的指针, *&a 解引用,向当于求整个数组的长度。
printf ("%d\n", sizeof(&a + 1)); //4
⑧ &a 为指向整个数组的指针, (&a + 1)指针加一还是指针,int型指针长度为4
printf ("%d\n", &a[0]); //4
⑨ a[0] 取数组的首元素,&a[0] 为指向首元素的地址,为 int* 型 长度为四个字节
printf ("%d\n", &a[0] + 1); //4
⑩ &a[0] 为指向首元素的指针(int*), 指针加一还是指针
2.字符数组,数组名指针转换求 sizeof 和 strlen
char arr[] = {'a' ,'b' , 'c', 'd', 'e', 'f'}; //初始化长度为6的字符数组
以下严格按照一行代码,再加一行解释的格式来书写
求sizeof
printf ("%d\n", sizeof(arr)); //6
① arr为字符数组名,取sizeof 为整个字符数组的长度,6个元素每个元素占一个字节。
printf ("%d\n", sizeof(arr + 0)); //4
② (arr + 0)数组名+数字,转换为指针, 占4个字节。
printf ("%d\n", sizeof(*arr)); //1
③ (*arr)数组名解引用,取到数组首元素 arr[0],字符'a',char型长度为1。
printf ("%d\n", sizeof(arr[1])); //1
④ arr[1] 取到数组第二个元素,字符 'b' ,长度为1个字节。
printf ("%d\n", sizeof(&arr)); //4
⑤ &arr 数组名取地址,转换为指针(数组指针), 长度为 4 字节。
printf ("%d\n", sizeof(&arr + 1)); //4
⑥ &arr + 1 ,指针(数组指针) + 或 - 数字,还是指针,长度为4。
printf ("%d\n", sizeof(&arr[0] + 1)); //4
⑦ arr[0] 为char型,&arr[0] 再取地址为 char* 型指针,char* + 1 还是指针 ,占4个字节。
求strlen
printf ("%d\n", strlen(arr));
printf ("%d\n", strlen(arr + 0));
printf ("%d\n", strlen(*arr));
printf ("%d\n", strlen(arr[1])); //未定义行为
printf ("%d\n", strlen(&arr));
printf ("%d\n", strlen(&arr + 1));
printf ("%d\n", strlen(&arr[0] + 1));
上面这串代码,对字符数组求 strlen,为非法行为(编译常说的未定义行为),这种操作在其他语言中是无法编译通过的。 因为strlen操作中,必须以读到 '\0' 来作为函数判断结束,字符数组并不是字符串以反杠零结尾。
3. 字符数组指向字符串,数组名指针转换,求 sizeof 和 strlen
char arr[] = "abcdef"; //字符数组指向长度为6的字符串
以下严格按照一行代码,再加一行解释的格式来书写
求sizeof
printf ("%d\n", sizeof(arr)); //7
① arr 数组名 求sizeof,为求整个字符串的长度,字符串以 '\0' 结尾,所以char型长度为 7。
printf ("%d\n", sizeof(arr + 0)); //4
② (arr + 0)数组名+数字,转换为指针, 占4个字节。
printf ("%d\n", sizeof(*arr)); //1
③(*arr)数组名解引用,取到数组首元素 arr[0],字符'a',char型长度为1。
printf ("%d\n", sizeof(arr[1])); //1
④ arr[1] 取字符串第二个元素 'b' ,char型长度为1。
printf ("%d\n", sizeof(&arr)); //4
⑤ &arr 数组名取地址,转换为指针(数组指针), 长度为 4 字节。
printf ("%d\n", sizeof(&arr + 1)); //4
⑥ &arr + 1 ,指针(数组指针) + 或 - 数字,还是指针,长度为4。
printf ("%d\n", sizeof(&arr + 1)); //4
⑦ arr[0] 为char型,&arr[0] 再取地址为 char* 型指针,char* + 1 还是指针 ,占4个字节。
求strlen
printf ("%d\n", strlen(arr)); //6
① 字符串求 strlen ,从首元素 读到 '\0' 结束。长度为 6
printf ("%d\n", strlen(arr + 0)); //6
② 数组名 + 或 - 数字,转换为指向这个元素的指针,此时指向首元素的指针,从此处往后找,到 '\0' 位置处结束。
① 和 ②在作用上是一致的。
printf ("%d\n", strlen(*arr)); //未定义行为
③ (*arr)数组名解引用,取到数组首元素 arr[0],此时取strlen无法 '\0' 来结尾 ,所以为非法行为。
printf ("%d\n", strlen(arr[1])); //未定义行为
④ 理由 同上, arr[1],此时取strlen无法 '\0' 来结尾 ,所以为非法行为。
printf ("%d\n", strlen(&arr)); //6
⑤ &arr为数组指针,指向数组的起始位置,取strlen 从此处开始往后找 '\0'的位置,取到长度为 6 。
printf ("%d\n", strlen(&arr + 1)); //未定义行为
⑥ 数组指针 + 1,表示跳过整个数组,即为指向 '\0' 后面位置的数组指针,再取strlen ,无法找到 '\0', 为非法行为。
printf ("%d\n", strlen(&arr[0] + 1)); //5
⑦ &arr[0]指向数组首元素的地址,&arr[0] + 1 指向数组第二个元素的地址。再取 strlen ,往后找到 '\0' 的地址,长度为5 。
4. char* 型数组名指向字符串,char*数组名与指针转换,求 sizeof 和 strlen
char* p = "abcdef"; //定义字符型指针变量p指向字符串
以下严格按照一行代码,再加一行解释的格式来书写
求sizeof
printf ("%d\n", sizeof(p)); //4
① p 为指针变量,sizeof(p) 长度即为 4 。
printf ("%d\n", sizeof(p + 1)); //4
② p + 1,指针加 1 还是指针,sizeof(p + 1)长度也为 4 。
printf ("%d\n", sizeof(*p)); //1
③ *p 解引用取到数组首元素 'a' ,长度为 1 。
printf ("%d\n", sizeof(p[0])); //1
④ 由 p[0] == *p,两个写法所指向内容相同, 'a' 长度为 1 。
printf ("%d\n", sizeof(&p)); //4
⑤ p 为指针类型变量,再取地址 &p 为二级指针,所以指针长度为 4 。
printf ("%d\n", sizeof(&p + 1)); //4
⑥ &p + 1,二级指针加 1 ,还是指针,长度为 4 。
printf ("%d\n", sizeof(&p[0] + 1)); //4
⑦ p[0] == *p ,解引用再取地址(&p[0]), 为char*,char* + 1长度还为 4 。
求strlen
printf ("%d\n", strlen(p)); //6
① p 为指针变量,指向数组首元素的地址,取strlen 从此处往后找 '\0' 的地址,即长度为 6 。
printf ("%d\n", strlen(p + 1)); //5
② p指向首元素地址,p + 1指向第二个元素地址,再取strlen 从此处往后找 '\0' 的地址,即长度为 5 。
printf ("%d\n", strlen(*p)); //未定义行为
③ *p == p[0] 取到 'a' ,无法找到 '\0' ,为非法操作 。
printf ("%d\n", strlen(p[0])); //未定义行为
④ p[0] == *p 取到 'a' ,无法找到 '\0' ,为非法操作 。
printf ("%d\n", strlen(&p)); //未定义行为
⑤ p 为指针类型变量,再取地址 &p 为二级指针,对类型求 strlen 为非法行为 。
printf ("%d\n", strlen(&p + 1)); //未定义行为
⑥ &p + 1,二级指针加 1 ,还是指针,对类型求 strlen 为非法行为 。
printf ("%d\n", strlen(&p[0] + 1)); //5
⑦ p[0] == *p ,解引用再取地址(&p[0]),此时为指向 'a' 的指针,(&p[0] + 1)为指向 'b' 的指针。再取strlen 从此处开始找到 '\0' 的地址,长度为 5 。
5. 二位整型数组,数组名与指针转换,求 sizeof 和 strlen
int a[3][4] = {0}; //表示长度为3的一维数组,每个元素是长度为4的一维数组
以下严格按照一行代码,再加一行解释的格式来书写
求sizeof
printf ("%d\n", sizeof(a)); //48
① 二维数组名取sizeof,共12个int型元素,长度为48 。
printf ("%d\n", sizeof(a[0][0])); //4
② a[0][0] 取第一行第一列的元素,为一个int,长度为4 。
printf ("%d\n", sizeof(a[0])); //16
③ 取第一行所以元素,第一行有4和元素,为4个int,长度为 16 。
printf ("%d\n", sizeof(a[0] + 1)); //4
④ 数组名 + 1,转换为指针。指针类型长度为 4 。
printf ("%d\n", sizeof(*(a[0] + 1))); //4
⑤ 等式转换 : *(p + 1) => p[1]
*(a[0] + 1) => a[0][1] ,指向第一行第二列的元素,一个int,长度为 4 。
printf ("%d\n", sizeof(a + 1)); //4
⑥ 数组名 + 1,转换为 指针,长度为 4 。
printf ("%d\n", sizeof(*(a + 1))); //16
⑦ *(a + 1) => a[1], 代表二维数组第二行的四个元素,四个int长度为 16 。
printf ("%d\n", sizeof(&a[0] + 1)); //4
⑧ &a[0] 数组名取地址,转换为数组指针,指针 + 1还是指针,长度为4 。
printf ("%d\n", sizeof(*(&a[0] + 1))); //4
⑨ *(&a[0] + 1) => (&a[0])[1],为取(&a[0])四个元素数组指针的第二个元素,即长度为4 。
printf ("%d\n", sizeof(*a)); //16
⑩ *a 取二维数组的首元素 a[0],为4个int,长度为16 。
printf ("%d\n", sizeof(a[3])); //16
上式 a[3],此处3为越界行为(3个元素取得时候只能是0 1 2),但此时为编译求值并不影响程序运行。
总结
1.数组名的意义
① sizeof(数组名),此处数组名表示对整个数组求大小。
② &数组名, 取的是整个数组的地址。
③ 除上面两种情况,其他所有的数组名都表示首元素的地址。
2.数组名和指针间的转换
① 数组名 加减 数字时,转换为指针。
② 数组名作为函数参数使用时,隐式转换为指向数组首元素的指针。
③ 数组名取地址,转换为指向整个数组首元素的数组指针。
3.几种等式相互转换
① 对于指针变量指向的字符数组: *数组名 == 数组名[0]。 //*p = p[0]
② 一维数组:*(数组名 + 1) == 数组名 [1]。 //*(p + 1) == p[1]
③ 二维数组:*(数组名[0] + 1) == 数组名[0][1] 。// *(a[0] + 1) == a[0][1]
④ 二维数组:*(&数组名[0] + 1) == (&数组名[0]) [1]。//*(&a[0] + 1) == (&a[0])[1]
4.指针数组与数组指针
指针数组
int* arr [10];
指针数组是一个数组,数组的每个元素都是一个指针。
数组指针
int (*arr)[10];
数组指针是 指针,这个指针指向十个元素的数组。