目录:C语言指针进阶训练
C语言指针小结
习题
习题1及讲解
习题2及讲解
习题3及讲解
习题4及讲解
习题5及讲解
C语言指针小结
① sizeof(数组名)——数组名代表整个数组的--计算的是整个数组的大小。
② &数组名——数组名表示整个数组,取出的是整个数组的地址。
(除此之外,所有的数组名都是数组首元素的地址)
习题
# include <stdio.h>
# include <string.h>
void test1()
{
int a[] = { 1, 2, 3, 4 };
printf("%d ", sizeof(a));
printf("%d ", sizeof(a + 0));
printf("%d ", sizeof(*a));
printf("%d ", sizeof(a + 1));
printf("%d ", sizeof(a[1]));
printf("%d ", sizeof(&a));
printf("%d ", sizeof(*&a));
printf("%d ", sizeof(&a + 1));
printf("%d ", sizeof(&a[0]));
printf("%d ", sizeof(&a[0] + 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 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 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 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]));
}
int main(void)
{
test1();
//test2();
//test3();
//test4();
//test5();
return 0;
}
习题1及讲解
# include <stdio.h>
# include <string.h>
void test1()
{
int a[] = { 1, 2, 3, 4 };
printf("%d\n", sizeof(a)); // 16
printf("%d\n", sizeof(a + 0)); // 4/8
printf("%d\n", sizeof(*a)); // 4
printf("%d\n", sizeof(a + 1)); // 4/8
printf("%d\n", sizeof(a[1])); // 4
printf("%d\n", sizeof(&a)); // 4/8
printf("%d\n", sizeof(*&a)); // 16
printf("%d\n", sizeof(&a + 1)); // 4/8
printf("%d\n", sizeof(&a[0])); // 4/8
printf("%d\n", sizeof(&a[0] + 1)); // 4/8
}
int main(void)
{
test1();
//test2();
//test3();
//test4();
//test5();
return 0;
}
解析:
- sizeof 直接对数组名 a 进行作用(sizeof(数组名)——数组名代表整个数组的--计算的是整个数组的大小),每个 int 所占字节大小为4个字节,数组 a 总共含有4个元素,每个元素所占空间为int( 4 )个字节,总共占16个字节。
- a+0表示的是第一个元素的地址,sizeof (a+0) 计算的是地址的大小。既然是地址,那么它所占大小就为4/8个字节(这里的4或8表示在32位上运行为4个字节大小,在64位上运行为8个字节大小)
- *a(对a进行解引用) 表示的是数组的第一个元素,sizeof(*a) 计算的是数组a中第一个元素的大小,第一个元素为int类型所占空间大小为4个字节,所以屏幕打印出的结果为4.
- (a+1)是第二个元素的地址,sizeof (a+1) 计算地址的大小。既然是地址,那么它所占大小就为4/8个字节。和2中sizeof (a+0) 同理。
- a[1] 代表的是第二个元素--2,这里 [1] 所表示的是序号为1所代表的元素,因为是从零开始的,所以1就是代表第二个元素,所占大小也为4个字节。
- sizeof(&a)(&数组名——数组名表示整个数组,取出的是整个数组的地址)这里 &a 虽然取出的是数组的地址,但也是地址,sizeof(&a)计算的是一个地址的大小。打印结果为4/8个字节。
- sizeof(*&a)先对a进行取地址操作,然后再解引用。计算的是数组的大小,可以理解为取地址和解引用之间相互抵消。所以就是sizeof (a) 结果为16。
- sizeof(&a+1)首先是对a进行取地址操作,然后&a+1 就是表示数组后面的空间地址,既然也是地址,那么地址所占空间大小也为4/8个字节。
9. sizeof(&a[0])这里的a[0]表示的是第一个元素,对第一个元素进行取地址操作,既然是地址,那么它所占大小还是为4/8个字节。
10.&a[0]类型是int*,&a[0]+1是进行4个字节的加减,起本质还是地址,所以,也还是4或8个字节。
习题2及讲解
# include <stdio.h>
# include <string.h>
void test2()
{
char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", sizeof(arr)); // 6
printf("%d\n", sizeof(arr + 0));// 4/8
printf("%d\n", sizeof(*arr)); // 1
printf("%d\n", sizeof(arr[1])); // 1
printf("%d\n", sizeof(&arr)); // 4/8
printf("%d\n", sizeof(&arr + 1)); // 4/8
printf("%d\n", sizeof(&arr[0] + 1)); // 4/8
printf("%d\n", strlen(arr)); //随机值
printf("%d\n", strlen(arr + 0)); //随机值
printf("%d\n", strlen(*arr)); //error
printf("%d\n", strlen(arr[1])); //error
printf("%d\n", strlen(&arr)); //随机值
printf("%d\n", strlen(&arr + 1)); //随机值-6
printf("%d\n", strlen(&arr[0] + 1)); //随机值-1
}
int main(void)
{
//test1();
test2();
//test3();
//test4();
//test5();
return 0;
}
- sizeof(arr)数组名单独放进去,计算的是数组的总大小,单位是字节arr总共有6个元素,每个元素为char类型,char所占字节大小为1字节,所以6个元素就为6个字节。(sizeof(数组名)——数组名代表整个数组的--计算的是整个数组的大小)
- 这里arr是代表首元素地址,arr+0还是首元素地址,sizeof 计算地址,大小为4/8个字节。
- sizeof(*arr) 这里arr没有单独放入sizeof 内部,所以这里arr代表的是首元素的地址,*arr--对首元素arr进行解引用,找到的是首元素,首元素是a,类型为char,所以打印结果为1.
- sizeof(arr[1]) 这里的arr[1]表示序号为1的,数组中从0开始序号1代表的是 ‘ b’ 类型为char,所以打印结果为1.
- sizeof(&arr) (&数组名——数组名表示整个数组,取出的是整个数组的地址)是地址的话,那么结果就是4/8.
- sizeof(&arr+1) 首先是对arr进行取地址操作,然后&arr+1 就是表示数组后面的空间地址,既然也是地址,那么地址所占空间大小也为4/8个字节。
7.sizeof(&arr[0]+1) 这里 arr[0]找到的是元素a,再进行取地址操作,所以取出的是元素a的地址,再进行+1操作,所以计算的就是第二个元素b的地址,是地址的话,也为4/8个字节。
8.strlen(arr) 这里arr代表的是首元素地址,strlen计算字符串长度,从第一个开始,向后依次进行计算,直到找到 ‘ \0 ’ 后停止。因为这里没有找到\0,所以结果就为随机值。
9.strlen(arr+0)这里arr代表的是首元素地址,arr+0就还是首元素地址,同上,结果也为随机值。
10.*arr表示对首元素的地址进行解引用,获得首元素的值,即a
但是strlen需要传入一个指针类型的变量,这里传入了一个a
,会引发报错error。
11.strlen(arr[1]) 代表的是字符b,同理也是传入字母b会报错。
12. strlen(&arr)( &数组名——数组名表示整个数组,取出的是整个数组的地址)取出的是arr的地址,向后找 \0 ,因为需要一直向后找,所以打印出来就是随机值。
13.strlen(&arr+1) ,&arr取出的是整个数组的地址,是数组指针,&arr+1指向的是下一个数组的地址,也就是从下一个地址开始向后数,找 \0 ,因为要向后一直找,所以结果就是随机值。也可以写为-6.
14.strlen(&arr[0]+1) 这里&arr[0]取出的是首元素的地址,而&arr[0]+1则是第二个的地址也是要从第二个地址开始,向后找 \0 ,因为是一直向后找的,所以打印出来的结果是随机值,也可以写成-1。
习题3及讲解
# include <stdio.h>
# include <string.h>
void test3()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); //7
printf("%d\n", sizeof(arr + 0)); //4/8
printf("%d\n", sizeof(*arr)); //1
printf("%d\n", sizeof(arr[1])); //1
printf("%d\n", sizeof(&arr)); //4/8
printf("%d\n", sizeof(&arr + 1)); //4/8
printf("%d\n", sizeof(&arr[0] + 1)); //4/8
printf("%d\n", strlen(arr)); //6
printf("%d\n", strlen(arr + 0)); //6
printf("%d\n", strlen(*arr)); //error
printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));//5
}
int main(void)
{
//test1();
//test2();
test3();
//test4();
//test5();
return 0;
}
解析:
- sizeof (arr) 数组名直接放入 sizeof 内部,满足结论一直接算数组的字节长度,这里 ‘a’、 ‘b’、 ‘c’、 ‘d’、 ‘e’、 ‘f’ char类型是占6个字节,但是这里容易忽视 ‘ \0 ’ ,它作为字符串的结束标志,也算一个字节大小。所以总共字节长度为7。
2.sizeof (arr+0)这里arr没有单独放到sizeof内部,所以不满足结论1和结论2,arr为首元素的地址,arr+0则还是为首元素的地址,其做为地址,所占空间大小就为4或8个字节。
3.sizeof (*arr) 这里的arr还是作为首元素的地址传入,而 ‘ * ’ 对首元素地址进行解引用操作,从而找到首元素,char类型所以这里打印出的结果是1。
4.sizeof (arr[1]) 这里arr[1] 所表示的是数组中编号为1的元素,a代表的是0,b代表的是1,所以这里其实就是传入的元素b,char类型,字节大小是1。
5.sizeof (&arr) 满足结论二( &数组名——数组名表示整个数组,取出的是整个数组的地址)既然是地址,那么它所占大小也为4或8个字节的空间。
6.sizeof (&arr+1) 取地址arr取出的是整个数组的地址,&arr+1则是跳过一个数组的地址,本质还是作为地址的,所以大小还是4或8个字节。
7.sizeof (&arr[0]+1) arr[0]表示的是首元素a,再进行取地址操作其实就是取出首元素a的地址,&arr[0]+1就是表示的b的地址,其也是作为地址的,所以所占空间大小其实也是4或者8个字节。
8.strlen(arr) 表示首元素字母的地址,那么首先是从首元素开始向后查,直到\0后停止,所以打印出的结果就是6。
9.strlen(arr+0) arr表示首元素的地址,+0还是表示首元素的地址,那么也是从首元素开始向后查,直到\0后停止,所以打印出的结果就是6。
10.strlen(*arr) 这里arr也是作为首元素的地址进行传入,再进行解引用操作,其就是传入的首元素a,strlen需要传入一个指针类型的变量,所以这里结果就会发生错误。
11.strlen(arr[1]) 这里的arr[1] 代表的是第二个元素b,strlen需要传入一个指针类型的变量,所以这里结果就会发生错误。其原理同上。
12.strlen(&arr) 适用于原理二(&数组名——数组名表示整个数组,取出的是整个数组的地址),从数组的起始位置开始,向后数,直到找到 \0 为止。所以结果就为6.
13.strlen(&arr+1) &(取地址)arr,取出的是整个数组的地址,然后再+1,跳过整个数组,然后再找 \0 ,程序一直处于寻找的状态,所以结果就是随机值。
14.strlen(&arr[0]+1) arr[0]表示的是首元素a,再进行取地址操作(&),取出首元素的地址,再加1则表示第二个元素的地址。从第二个元素地址向后数,数到 \0 后停止,所以结果就是5。
习题4及讲解
# include <stdio.h>
# include <string.h>
void test4()
{
char* p = "abcdef";
printf("%d\n", sizeof(p)); //4/8
printf("%d\n", sizeof(p + 1)); //4/8
printf("%d\n", sizeof(*p)); //1
printf("%d\n", sizeof(p[0])); //1
printf("%d\n", sizeof(&p)); //4/8
printf("%d\n", sizeof(&p + 1)); //4/8
printf("%d\n", sizeof(&p[0] + 1)); //4/8
printf("%d\n", strlen(p)); //6
printf("%d\n", strlen(p + 1)); //5
printf("%d\n", strlen(*p)); //error
printf("%d\n", strlen(p[0])); //error
printf("%d\n", strlen(&p)); //随机值
printf("%d\n", strlen(&p + 1)); //随机值
printf("%d\n", strlen(&p[0] + 1)); //5
}
int main(void)
{
//test1();
//test2();
//test3();
test4();
//test5();
return 0;
}
解析:
- sizeof(p),p 是地址,地址所占大小为4或8个字节。
- sizeof(p+1),(p+1)所表示的是 b 的地址,p首先为 a 的地址,地址的大小就是4或8个字节。
- sizeof(*p) ,这里的 p 代表首元素的地址,对 p 进行解引用操作,得到的就是 a,类型是char类型,所以大小就为1个字节。
- sizeof(p[0]) ,p[0]代表的是首元素 a ,*(p+0) 也是 a,所以大小就为1个字节。
- sizeof(&p) ,这里取出的是p的地址,其本质上还是地址,是地址的话,其大小就是4或8个字节。
- sizeof(&p+1) ,取地址(&)p是取出p的地址,然后再加一,则是跳出p的地址,拿到的还是地址,大小还是4或8个字节。
- sizeof(&p[0]+1) ,p[0]代表的是第一个元素a,取地址(&)取出的是元素a的地址,然后+1则是b的地址,也还是地址,所以也是4或8个字节的大小。
- strlen(p) ,求的是字符串的大小,从首元素字母开始向后查找,查找到 ‘\0’ 后停止,所以打印出的结果为6.
- strlen(p+1),这里的p是首元素字母,(p+1)所代表的就是第二个元素b,从第二个元素开始向后查找 ‘\0’ ,字符串长就为5。
- strlen(*p) ,这里的p代表的是首元素的地址,再对其进行解引用操作,找到的就是首元素a,a的阿斯克码表值为97,传入的其实是数字97,所以结果会发生错误。
- strlen(p[0]) ,p[0]所表示的也是首元素字母a,所以其原理同上。
- strlen(&p) ,对p指针进行取地址操作,p里面存的 是什么都不知道,所以打印出的结果是随机值。
13.strlen(&p+1),p中存放a的地址,&P取出的是存放p指针的地址,&p+1指向p后面的一个地址,这里不知道后续的内存中存储了什么值,直到遇到 ‘\0’ 才停,所以就出现了随机值。
14.strlen(&p[0]+1) ,&p[0]取出的是第一个元素的地址,然后+1是从b的地址向后数找 ‘\0’,所以结果就是5.
习题5及讲解
# include <stdio.h>
# include <string.h>
void test5()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a)); //48
printf("%d\n", sizeof(a[0][0])); //4 第一行第一列的元素
printf("%d\n", sizeof(a[0])); //16 第一行的元素
printf("%d\n", sizeof(a[0] + 1)); //4/8 第一行第二个元素的地址
printf("%d\n", sizeof(*(a[0] + 1))); //4 第一行第二个元素的值
printf("%d\n", sizeof(a + 1)); //4/8 第二行的元素的地址
printf("%d\n", sizeof(*(a + 1))); //16 第二行的元素
printf("%d\n", sizeof(&a[0] + 1)); //8 第二行元素的地址,为什么和a2[0] + 1的结果不一样呢?
//这是因为&a2[0]获得的指针类型是数组指针,+1会跳过整个一行,
//而a2[0]是普通的int类型指针,+1跳过4个字节,获得下一个元素的地址。
printf("%d\n", sizeof(*(&a[0] + 1))); //16 第二行的元素
printf("%d\n", sizeof(*a)); //16 第一行的元素
printf("%d\n", sizeof(a[3])); //16 第四行的元素
}
int main(void)
{
//test1();
//test2();
//test3();
//test4();
test5();
return 0;
}
解析:
- sizeof(a),其代表的是计算整个数组的大小,3×4×sizeof(int)=48.
- sizeof(a[0][0]),代表的就是第一行第一个元素,int类型的在内存中所占大小为4个字节。
- sizeof(a[0]),表示的是第一行,二维数组三行四列,第一行也就有4个元素,一个为int类型大小为4个字节,所以总的就为4×4=16字节。
- sizeof(a[0]+1) , a[0]作为数组名没有单独放在sizeof内部,也没取地址,所以a[0]就是第一行第一个的地址,a[0]+1就是第一行第二个元素的地址。是地址的话结果就为4个字节。
- sizeof *(a[0]+1) , (a[0]+1)是第一行第二个元素的地址,在对其进行解引用操作,找到的就是第一行第二个元素,结果也是4个字节。
- sizeof (a+1),a是二维数组的数组名,并没有取地址,也没有单独放在sizeof内部,所以a就是表示二维数组首元素的地址(第一行的地址),a+1就是二维数组第二行的地址。是地址的话,大小就为4/8个字节。
- sizeof *(a+1) ,a+1是第二行地址,对其进行解引用操作就是计算第二行大小。4×4=16.
- sizeof (&(a+1)),a是二维数组的数组名,也没有单独放在sizeof内部,所以a就是表示二维数组首元素的地址(第一行的地址),a+1就是二维数组第二行的地址。是地址的话,大小就为4/8个字节。
- sizeof (&a[0]+1),取地址(&)a[0] ,取出第一行的地址,&a[0]+1就是第二行的地址,是地址的话,要么是4个字节,要么是8个字节。
- sizeof *(&a[0]+1),取地址(&)a[0] ,取出第一行的地址,&a[0]+1就是第二行的地址,再进行解引用操作,找到的就是第二行元素,所占大小就是4×4=16字节。
- sizeof(*a) ,a作为二维数组的数组名,没有取地址,也没有单独放到sizeof内部,a代表的就是首元素地址,对首元素进行解引用操作,找到的就是第一行的元素,其所占大小是4×4=16个字节。
- sizeof(a[3]) ,a[3]其实代表的是第四行的数组名(如果有的话),所以其实不存在,也能通过类型计算大小的。其计算结果就是16个字节。
以上就是本篇文章的全部内容了,如果感觉还不错,请给个赞,加个关注,希望以后能为大家呈现更好的文章。^_^