C语言指针进阶训练

目录: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;
}

解析:

  1. sizeof 直接对数组名 a 进行作用(sizeof(数组名)——数组名代表整个数组的--计算的是整个数组的大小),每个 int 所占字节大小为4个字节,数组 a 总共含有4个元素,每个元素所占空间为int( 4 )个字节,总共占16个字节。
  2. a+0表示的是第一个元素的地址,sizeof (a+0) 计算的是地址的大小。既然是地址,那么它所占大小就为4/8个字节(这里的4或8表示在32位上运行为4个字节大小,在64位上运行为8个字节大小)
  3. *a(对a进行解引用) 表示的是数组的第一个元素,sizeof(*a) 计算的是数组a中第一个元素的大小,第一个元素为int类型所占空间大小为4个字节,所以屏幕打印出的结果为4.
  4. (a+1)是第二个元素的地址,sizeof (a+1) 计算地址的大小。既然是地址,那么它所占大小就为4/8个字节。和2中sizeof (a+0) 同理。
  5. a[1] 代表的是第二个元素--2,这里 [1] 所表示的是序号为1所代表的元素,因为是从零开始的,所以1就是代表第二个元素,所占大小也为4个字节。
  6. sizeof(&a)(&数组名——数组名表示整个数组,取出的是整个数组的地址)这里 &a 虽然取出的是数组的地址,但也是地址,sizeof(&a)计算的是一个地址的大小。打印结果为4/8个字节。
  7. sizeof(*&a)先对a进行取地址操作,然后再解引用。计算的是数组的大小,可以理解为取地址和解引用之间相互抵消。所以就是sizeof (a) 结果为16。
  8. 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;
}

  1. sizeof(arr)数组名单独放进去,计算的是数组的总大小,单位是字节arr总共有6个元素,每个元素为char类型,char所占字节大小为1字节,所以6个元素就为6个字节。(sizeof(数组名)——数组名代表整个数组的--计算的是整个数组的大小
  2. 这里arr是代表首元素地址,arr+0还是首元素地址,sizeof 计算地址,大小为4/8个字节。
  3. sizeof(*arr) 这里arr没有单独放入sizeof 内部,所以这里arr代表的是首元素的地址,*arr--对首元素arr进行解引用,找到的是首元素,首元素是a,类型为char,所以打印结果为1.
  4. sizeof(arr[1]) 这里的arr[1]表示序号为1的,数组中从0开始序号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的地址,再进行+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;
}

解析:

  1. 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;
}

解析:

  1. sizeof(p),p 是地址,地址所占大小为4或8个字节。
  2. sizeof(p+1),(p+1)所表示的是 b 的地址,p首先为 a 的地址,地址的大小就是4或8个字节。                                                                                                                                                         
  3. sizeof(*p) ,这里的 p 代表首元素的地址,对 p 进行解引用操作,得到的就是 a,类型是char类型,所以大小就为1个字节。
  4. sizeof(p[0]) ,p[0]代表的是首元素 a ,*(p+0) 也是 a,所以大小就为1个字节。
  5. sizeof(&p) ,这里取出的是p的地址,其本质上还是地址,是地址的话,其大小就是4或8个字节。                                                                                                                                            
  6. sizeof(&p+1) ,取地址(&)p是取出p的地址,然后再加一,则是跳出p的地址,拿到的还是地址,大小还是4或8个字节。
  7. sizeof(&p[0]+1) ,p[0]代表的是第一个元素a,取地址(&)取出的是元素a的地址,然后+1则是b的地址,也还是地址,所以也是4或8个字节的大小。
  8. strlen(p) ,求的是字符串的大小,从首元素字母开始向后查找,查找到 ‘\0’ 后停止,所以打印出的结果为6.
  9. strlen(p+1),这里的p是首元素字母,(p+1)所代表的就是第二个元素b,从第二个元素开始向后查找 ‘\0’ ,字符串长就为5。
  10. strlen(*p) ,这里的p代表的是首元素的地址,再对其进行解引用操作,找到的就是首元素a,a的阿斯克码表值为97,传入的其实是数字97,所以结果会发生错误。
  11. strlen(p[0]) ,p[0]所表示的也是首元素字母a,所以其原理同上。
  12. 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;
}

解析:

  1. sizeof(a),其代表的是计算整个数组的大小,3×4×sizeof(int)=48.
  2. sizeof(a[0][0]),代表的就是第一行第一个元素,int类型的在内存中所占大小为4个字节。
  3. sizeof(a[0]),表示的是第一行,二维数组三行四列,第一行也就有4个元素,一个为int类型大小为4个字节,所以总的就为4×4=16字节。                                                                                          
  4. sizeof(a[0]+1) , a[0]作为数组名没有单独放在sizeof内部,也没取地址,所以a[0]就是第一行第一个的地址,a[0]+1就是第一行第二个元素的地址。是地址的话结果就为4个字节。            
  5. sizeof *(a[0]+1) , (a[0]+1)是第一行第二个元素的地址,在对其进行解引用操作,找到的就是第一行第二个元素,结果也是4个字节。
  6. sizeof (a+1),a是二维数组的数组名,并没有取地址,也没有单独放在sizeof内部,所以a就是表示二维数组首元素的地址(第一行的地址),a+1就是二维数组第二行的地址。是地址的话,大小就为4/8个字节。
  7. sizeof *(a+1) ,a+1是第二行地址,对其进行解引用操作就是计算第二行大小。4×4=16.
  8. sizeof (&(a+1)),a是二维数组的数组名,也没有单独放在sizeof内部,所以a就是表示二维数组首元素的地址(第一行的地址),a+1就是二维数组第二行的地址。是地址的话,大小就为4/8个字节。
  9. sizeof (&a[0]+1),取地址(&)a[0] ,取出第一行的地址,&a[0]+1就是第二行的地址,是地址的话,要么是4个字节,要么是8个字节。
  10. sizeof *(&a[0]+1),取地址(&)a[0] ,取出第一行的地址,&a[0]+1就是第二行的地址,再进行解引用操作,找到的就是第二行元素,所占大小就是4×4=16字节。
  11. sizeof(*a) ,a作为二维数组的数组名,没有取地址,也没有单独放到sizeof内部,a代表的就是首元素地址,对首元素进行解引用操作,找到的就是第一行的元素,其所占大小是4×4=16个字节。
  12. sizeof(a[3]) ,a[3]其实代表的是第四行的数组名(如果有的话),所以其实不存在,也能通过类型计算大小的。其计算结果就是16个字节。

以上就是本篇文章的全部内容了,如果感觉还不错,请给个赞,加个关注,希望以后能为大家呈现更好的文章。^_^

  • 17
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值