前言
在理解 C语言指针 的这篇文章的基础上,做下面的练习题可以更好地掌握数组与指针的知识。
七、练习
数组名表示数组首元素的地址
但是有2个例外:
- sizeof(数组名),数组名表示整个数组,计算的是数组的总大小,单位是字节。
- &数组名,数组名表示整个数组,&数组名 取出的是整个数组的地址
除此之外,所有遇到的数组名都表示数组首元素的地址。
*(arr + n) = arr[n]
7.1 一维数组
void test1()
{
int a[] = { 1,2,3,4 };
printf("%d\r\n", sizeof(a));
printf("%d\r\n", sizeof(a + 0));
printf("%d\r\n", sizeof(*a));
printf("%d\r\n", sizeof(a + 1));
printf("%d\r\n", sizeof(a[1]));
printf("%d\r\n", sizeof(&a));
printf("%d\r\n", sizeof(*&a));
printf("%d\r\n", sizeof(&a + 1));
printf("%d\r\n", sizeof(&a[0]));
printf("%d\r\n", sizeof(&a[0] + 1));
}
void test1()
{
int a[] = { 1,2,3,4 };
// sizeof(数组名)计算的是数组的总大小
printf("%d\r\n", sizeof(a)); // 16
// 数组名a是数组首元素的地址,32位程序的地址是4字节
printf("%d\r\n", sizeof(a + 0)); // 4
// 数组名a是数组首元素的地址,*a得到数组的首元素1,类型为int大小4字节
// *(arr + n) = arr[n] 因此 *a=*(a+0)=a[0]
printf("%d\r\n", sizeof(*a)); // 4
// 数组名a是数组首元素的地址,a+1得到下一个元素的地址,地址为4字节大小
printf("%d\r\n", sizeof(a + 1)); // 4
// 数组元素类型为int大小4字节
printf("%d\r\n", sizeof(a[1])); // 4
// &数组名表示整个数组的地址,地址为4字节大小
printf("%d\r\n", sizeof(&a)); // 4
// &a为整个数组的地址,再解星号得到整个数组,相当于*与&抵消了,数组大小为16字节
printf("%d\r\n", sizeof(*&a)); // 16
// &a为整个数组的地址,加1得到越过数组a之后的地址,地址大小4字节
printf("%d\r\n", sizeof(&a + 1)); // 4
// 数组首元素的地址,地址大小4字节
printf("%d\r\n", sizeof(&a[0])); // 4
// 数组首元素的地址,类型为int*,加1表示下一个元素的地址,地址大小4字节
printf("%d\r\n", sizeof(&a[0] + 1)); // 4
}
7.2 字符数组1
void test2()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
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));
}
参考:
void test2()
{
char arr[] = { 'a','b','c','d','e','f' };
// sizeof(数组名)计算整个数组的大小
printf("%d\n", sizeof(arr)); // 6
// 数组名arr表示数组首元素的地址,加0还是数组首元素的地址,地址4字节大小
printf("%d\n", sizeof(arr + 0)); // 4
// arr表示数组首元素的地址,*arr得到数组首元素a,类型为char大小1字节
printf("%d\n", sizeof(*arr)); // 1
// 数组下标为1的元素为b,类型为char大小1字节
printf("%d\n", sizeof(arr[1])); // 1
// &arr为整个数组的地址,地址4字节大小
printf("%d\n", sizeof(&arr)); // 4
// &arr为整个数组的地址,加1得到越过整个数组的地址,地址大小4字节
printf("%d\n", sizeof(&arr + 1)); // 4
// 数组首元素的地址,加1得到下一个元素的地址,地址大小4字节
printf("%d\n", sizeof(&arr[0] + 1)); // 4
// arr数组首元素的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(arr)); // 随机数,测试为19
// 数组名arr表示数组首元素的地址,加0还是数组首元素的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(arr + 0)); // 随机数,测试为19
// 数组名arr表示数组首元素的地址,*arr得到首元素a,a作为strlen的参数,将计算地址为a的ascii码值97=0x61处字符串长度,将会出现内存访问异常的错误,error
printf("%d\n", strlen(*arr));
// 同上,将计算地址为b的ascii码值98=0x62处字符串长度,出现内存访问异常,error
printf("%d\n", strlen(arr[1]));
// &arr取得整个数组的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(&arr)); // 随机数,测试为19
// &arr取得整个数组的地址,加1得到越过整个数组的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(&arr + 1)); // 随机数,测试为13
// 数组首元素的地址,加1得到下一个元素的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(&arr[0] + 1)); // 随机数,测试为18
}
7.3 字符数组2
void test3()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
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));
}
参考:
void test3()
{
char arr[] = "abcdef"; // 字符串在栈区,其自动包括'\0'
// sizeof(数组名)计算整个数组的大小
printf("%d\n", sizeof(arr)); // 7
// 数组名是数组首元素的地址,加0还是首元素的地址,地址大小4字节
printf("%d\n", sizeof(arr + 0)); // 4
// arr表示数组首元素的地址,*arr得到数组首元素a,类型为char大小1字节
printf("%d\n", sizeof(*arr)); // 1
// 数组下标为1的元素为b,类型为char大小1字节
printf("%d\n", sizeof(arr[1])); // 1
// &arr为整个数组的地址,地址4字节大小
printf("%d\n", sizeof(&arr)); // 4
// &arr为整个数组的地址,加1得到越过整个数组的地址,地址大小4字节
printf("%d\n", sizeof(&arr + 1)); // 4
// 数组首元素的地址,加1得到下一个元素的地址,地址大小4字节
printf("%d\n", sizeof(&arr[0] + 1)); // 4
// arr数组首元素的地址,strlen遇到'\0'结束,得到的长度不包括'\0'
printf("%d\n", strlen(arr)); // 6
// 数组名arr表示数组首元素的地址,加0还是数组首元素的地址,strlen遇到'\0'结束,得到的长度不包括'\0'
printf("%d\n", strlen(arr + 0)); // 6
// 数组名arr表示数组首元素的地址,*arr得到首元素a,a作为strlen的参数,将计算地址为a的ascii码值97=0x61处字符串长度,将会出现内存访问异常的错误,error
printf("%d\n", strlen(*arr)); // error
// 同上,将计算地址为b的ascii码值98=0x62处字符串长度,出现内存访问异常,error
printf("%d\n", strlen(arr[1])); // error
// &arr取得整个数组的地址,strlen遇到'\0'结束,得到的长度不包括'\0'
printf("%d\n", strlen(&arr)); // 6
// &arr取得整个数组的地址,加1得到越过整个数组的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(&arr + 1)); // 随机数,测试为12
// 数组首元素的地址,加1得到下一个元素的地址,strlen遇到'\0'结束,得到的长度不包括'\0'
printf("%d\n", strlen(&arr[0] + 1)); // 5
}
7.4 字符串指针
void test4()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p + 1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
}
参考:
void test4()
{
char* p = "abcdef";
// p指向字符串首地址,地址大小4字节
printf("%d\n", sizeof(p)); // 4
// p指向字符串首地址,加1指向下一个元素地址,地址大小4字节
printf("%d\n", sizeof(p + 1)); // 4
// p指向字符串首地址,*p取得字符串首元素,类型为char大小1字节。*p=*(p+0)=p[0]
printf("%d\n", sizeof(*p)); // 1
// 字符串首元素,类型为char大小1字节
printf("%d\n", sizeof(p[0])); // 1
// &p得到指针变量p在栈中的地址,地址大小4字节
printf("%d\n", sizeof(&p)); // 4
// &p得到指针变量p在栈中的地址,加1取得栈中p的下一个地址,类型为char**大小4字节
printf("%d\n", sizeof(&p + 1)); // 4
// 字符串首元素的地址,加1得到下一个元素的地址,类型为char*大小4字节
printf("%d\n", sizeof(&p[0] + 1)); // 4
// p指向字符串首地址,strlen遇到'\0'结束,得到的长度不包括'\0'
printf("%d\n", strlen(p)); // 6
// p指向字符串首地址,加1得到下一个元素的地址,即指向b
printf("%d\n", strlen(p + 1)); // 5
// p指向字符串首地址,*p取得字符串首元素a,a作为strlen的参数,将计算地址为a的ascii码值97=0x61处字符串长度,将会出现内存访问异常的错误,error
printf("%d\n", strlen(*p)); // error
// 同上,将计算地址为b的ascii码值98=0x62处字符串长度,出现内存访问异常,error
printf("%d\n", strlen(p[0])); // error
// &p得到指针变量p在栈中的地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(&p)); // 随机数,测试为3
// &p得到指针变量p在栈中的地址,加1取得栈中p的下一个地址,因'\0'位置不知,下面是一个随机数
printf("%d\n", strlen(&p + 1)); // 随机数,测试为11
// 字符串首元素的地址,加1得到下一个元素的地址,即b的地址
printf("%d\n", strlen(&p[0] + 1)); // 5
}
7.5 二维数组
void test5()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[3]));
}
参考:
void test5()
{
int a[3][4] = { 0 };
// sizeof(数组名)计算整个数组的大小
printf("%d\n", sizeof(a)); // 48
// 二维数组a的首元素为a[0],一维数组a[0]的首元素a[0][0]类型int大小4字节
printf("%d\n", sizeof(a[0][0])); // 4
// a[0]为二维数组的首元素,也是个一维数组,类型为int[4],sizeof(数组名)得到计算整个数组的大小
printf("%d\n", sizeof(a[0])); // 16
// a[0]为一维数组,数组名表示数组首元素的地址,加1表示下一个元素的地址,等价于&a[0][0]+1,即a[0][1]的地址
printf("%d\n", sizeof(a[0] + 1)); // 4
// a[0]为一维数组,数组名为数组首元素的地址,加1得到下一个元素的地址,*得到地址对应的值,即a[0][1]处的值,类型为int大小4字节
printf("%d\n", sizeof(*(a[0] + 1))); // 4
// 二维数组名a表示数组首元素a[0]的地址,加1表示数组a下一个元素的地址,即a[1]的地址
printf("%d\n", sizeof(a + 1)); // 4
// a+1得到a[1]的地址,*得到一维数组a[1],其中有4个int型元素,sizeof(数组名)得到计算整个数组的大小。相当于sieof(a[1])
printf("%d\n", sizeof(*(a + 1))); // 16
// a[0]是一维数组,&a[0]得到整个数组的地址,加1得到越过一维数组a[0]的地址,即a[1]的地址
printf("%d\n", sizeof(&a[0] + 1)); // 4
// &a[0]+1得到a[1]的地址,*得到一维数组a[1],其中有4个int型元素,sizeof(数组名)得到计算整个数组的大小。
printf("%d\n", sizeof(*(&a[0] + 1))); // 16
// 二维数组名a表示数组首元素a[0]的地址,*得到首元素一维数组a[0],其中有4个int型元素,sizeof(数组名)得到计算整个数组的大小。*a=*(a+0)=a[0] sizeof(*a)=sizeof(a[0])
printf("%d\n", sizeof(*a)); // 16
// a[3]的类型为int[4]
printf("%d\n", sizeof(a[3])); // 16
}
7.6 数组指针
数组指针可以接收二维数组。理解了上面的二维数组,下面的题就不是很难了,因此我就不写分析了,感兴趣的可以自己分析。
主要应用:*(arr + n) = arr[n]
void test6()
{
int nAry[2][4] = {
{10,20,30,40},
{60,70,80,90}
};
int(*p)[4] = nAry;
printf("%p\r\n", p);
printf("%p\r\n", *p);
printf("%p\r\n", (void*)**p);
printf("%p\r\n", (void*)sizeof(p));
printf("%p\r\n", (void*)sizeof(*p));
printf("%p\r\n", (void*)sizeof(**p));
printf("%p\r\n", p + 1);
printf("%p\r\n", *p + 1);
printf("%p\r\n", (void*)(**p + 1));
printf("%p\r\n", p[1] + 1);
printf("%p\r\n", (void*)*((p + 1)[1]));
printf("%p\r\n", (void*)(*(p + 1))[1]);
// 下标运算的优先级比*运算的优先级高
printf("%p\r\n", (void*)(*p[1] + 1));
printf("%p\r\n", (void*)(p[1] + 1)[1]);
}