指针题_c

本文是我在学习c语言指针时遇到的一些有难度的题目,我水平有限,有的地方没说清请见谅!

1.strlen函数和sizeof运算符

首先是stlen,

让我们打开cplusplus网站搜索这两个函数。

 //Fuck you ,English

让我们使用百度来翻译一下

 //Fuck!!!

还是查词典吧

来理解以一下这段文字,就是说你如果想调用这个函数的话,需要传入一个指向字符串首元素的char*类型的指针,它会返回这个字符串的长度,返回值是size_t类型(size_t是unsigned int 类型重命名,用%zd打印)。它的实现方法返回从起始地址到下一个指向'\0'的地址的距离,不包含'\0'。

sizeof

sizeof是一个运算符,传入一个数据,会返回这个数据所占内存大小。sizeof只是计算传入的类型的大小,传入的数据不会真的去计算,不会越界访问,返回值也i为size_t类型

#include<stdio.h>
#include<string.h>
int main()
{

	int n = 10;
	printf("%zd\n", sizeof(n++));
	printf("%d\n", n);//10

	return 0;
}

因为sizeof是运算符,所以当传入数据时它后面可以不加括号,传入数据类型必须加括号

#include<stdio.h>
#include<string.h>
int main()
{
	int a = 0;
	printf("%zd\n", sizeof(a));//4
	printf("%zd\n", sizeof a);//4
	printf("%zd\n", sizeof(int));//4
	//printf("%zd\n", sizeof int);//报错

	return 0;
}

sizeof()在c语言中为第二优先级,比加减乘除优先级要高,能加括号还是建议加括号

stlen和sizeof对比

#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = {"abc'\0'123456"};
	printf("%zd\n", sizeof(arr1));//13
	printf("%zd\n", strlen(arr1));//4

	char arr2[] = {'a','b','c','d'};
	printf("%zd\n", sizeof(arr2));//4
	printf("%zd\n", strlen(arr2));//随机值

	return 0;
}

​

​

2指针

2.1

#include<stdio.h>
#include<string.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%zd\n", sizeof(a));//1
	printf("%zd\n", sizeof(a + 0));//2
	printf("%zd\n", sizeof(*a));//3
	printf("%zd\n", sizeof(a + 1));//4
	printf("%zd\n", sizeof(a[1]));//5
	printf("%zd\n", sizeof(&a));//6
	printf("%zd\n", sizeof(*&a));//7
	printf("%zd\n", sizeof(&a + 1));//8
	printf("%zd\n", sizeof(&a[0]));//9
	printf("%zd\n", sizeof(&a[0] + 1));//10
	return 0;
}

a是一个整形数组内部含有四个元素

2.1.1 sizeof(a)

当数组名单独位于sizof内部时,数组名代表整个数组,求a数组所占内存大小,一个int四个字节,四个元素所以一共16字节。

返回16.

2.1.2 sizeof(a+0)

此时a+0放在sizeof内部,a为首元素地址,地址的话32位机子为4字节,64位为8字节。

返回 4/8 

2.1.3 sizeof(*a)

a表示首元素地址,*a表示首元素,也就是int型的1.一个int4字节

返回 4

2.1.4 sizeof(a+1)

a+1放在sizeof内部,a为首元素地址,a+1为 a[1] 的地址,地址的话~~~

返回 4/8 

2.1.5 sizeof(a[1])

a[1]为 int 的 2 。一个int~~~

返回 4

2.1.6 sizeof(&a)

&数组名会取出整个数组的地址,地址~~~

返回 4/8 

2.1.7 sizeof(*&a)

&a 取出数组的地址*&a把这个地址解引用,得到整个数组,这个数组4个int一个共16字节

返回 16

2.1.8 sizeof(&a + 1)

&a拿出这个数组的地址,再+1跳过这个数组,指向这个数组后面,虽然它指的地方越界了,但是sizeof()括号内的语句不会真的去执行,对于系统来说,这只是要求一个指针占的的内存大小。指针~~~

返回 4/8

2.1.9.sizeof(&a[0])

下标运算符 [] 比 取地址运算符 &优先级高.a[0]为首元素,&a[0]为首元素地址,地址的话

返回4/8

2.1.10.sizeof(&a[0]+1)

&优先级比+高,接着上一题分析&a[0]为首元素地址,&a[0]+1为第二元素的地址。

返回4/8

答案我检查过了,没问题,不过还是建议读者去敲一敲。

2.2

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
    printf("%zd\n", sizeof(arr));//1
    printf("%zd\n", sizeof(arr + 0));//2
    printf("%zd\n", sizeof(*arr));//3
    printf("%zd\n", sizeof(arr[1]));//4
    printf("%zd\n", sizeof(&arr));//5
    printf("%zd\n", sizeof(&arr + 1));//6
    printf("%zd\n", sizeof(&arr[0] + 1));//7
    return  0;
}

arr是字符数组含有6个元素

2.2.1。sizeof(arr)

数组名放在sizeof内部代表整个数组,arr有6个char类型数据,一个char占一个字节,故6个字节

返回6

2.2.2 sizeof(arr+0)

此时arr为首元素地址,arr+0后内容不变,故该值是一个指向首元素的指针

返回4/8

2.2.3sizeof(*arr)

arr为首元素地址,*arr代表这个地址解引用,是一个char元素

返回1

2.2.4sizeof(arr[1])

arr[1]为该字符数组第二个元素,类型为char 

返回1

2.2.5sizeof(&arr)

&arr得到的是指向arr数组的指针,

返回4/8

2.2.6sizeof(&arr+1)

&arr得到指向数组的指针,&arr+1跳过一个数组,它是一个指向arr后面的指针。sizeof只关心后面元素的数据类型,并不在意是否越界。

返回4/8

2.2.7sizeof(&arr[0]+1)

查运算符优先级表得:先下标,再&,最后+。arr[0]为首元素,&arr[0]为首元素地址,&arr[0]+1为第二个元素的地址

返回4/8

2.3

ps:4,5不能过编译

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };//1
	printf("%zd\n", strlen(arr));//2
	printf("%zd\n", strlen(arr + 0));//3
	printf("%zd\n", strlen(*arr));//4
	printf("%zd\n", strlen(arr[1]));//5
	printf("%zd\n", strlen(&arr));//6
	printf("%zd\n", strlen(&arr + 1));//7
	printf("%zd\n", strlen(&arr[0] + 1));//8
	return 0;
}
2.3.1stlen(arr)

arr为首元素地址,stlen会从传入地址开始往后找,一直找到一个解引用后是\0的返回中间地址之差因为没有往数组里面放‘0‘,所以它会越界访问,直到找到’0‘(或者电脑炸掉,不过可能性不大)

返回         一个>=6的随机值  (假入把这个值记为random_8_19的话)

2.3.2stlen(arr+0)

arr+0仍然是首元素地址,所以同上。

返回               随机值               (值为random_8_19)

2.3.3stlen(*arr)

arr为首元素地址,*arr为首元素,是一个字符。

传参有误,报错

2.3.4stlen(arr[1])

arr[1]为第二个元素,也为字符

传参有误,报错

2.3.5stlen(&arr)

&arr代表arr数组的地址,数组的地址和数组开头的地址是一样的,所以会从数组开头开始找’0‘

返回        随机        (random_8_19)

2.3.6stlen(&arr+1)

&arr+1会跳过数组,指向数组后面的元素,所以会从数组后面开始查找'\0'

返回        随机值        (rand_8_19-6)

2.3.7strlen(&arr[0]+1)

&arr[0]代表首元素地址,+1跳过一个元素

返回        随机值        (rand_8_19-1)

2.4

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%zd\n", sizeof(arr));//1
	printf("%zd\n", sizeof(arr + 0));//2
	printf("%zd\n", sizeof(*arr));//3
	printf("%zd\n", sizeof(arr[1]));//4
	printf("%zd\n", sizeof(&arr));//5
	printf("%zd\n", sizeof(&arr + 1));//6
	printf("%zd\n", sizeof(&arr[0] + 1));//7

	return 0;
}

arr数组含有7个char元素,最后一个是‘\0'

此题与2.2相似,不做过多讲解,

答案为7,        4/8,        1,        1,        4/8        ,4/8       , 4/8

2.5

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%zd\n", strlen(arr));
	printf("%zd\n", strlen(arr + 0));
	printf("%zd\n", strlen(*arr));
	printf("%zd\n", strlen(arr[1]));
	printf("%zd\n", strlen(&arr));
	printf("%zd\n", strlen(&arr + 1));
	printf("%zd\n", strlen(&arr[0] + 1));

	return 0;
}

arr数组含有7个char元素,最后一个是‘\0'

此题与2.3类似

答案6        6        报错        报错        6                随机值        5

2.6

#include<stdio.h>
#include<string.h>
int main()
{
	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));
	return 0;
}

p指向该数组的首元素'a',该数组含有7个char元素,最后一个是‘\0'

解析略

4/8        4/8        1        1        4/8        4/8        4/8

2.7

#include<stdio.h>
#include<string.h>
int main()
{

	char* p = "abcdef";
	printf("%zd\n", strlen(p));
	printf("%zd\n", strlen(p + 1));
	printf("%zd\n", strlen(*p));
	printf("%zd\n", strlen(p[0]));
	printf("%zd\n", strlen(&p));
	printf("%zd\n", strlen(&p + 1));
	printf("%zd\n", strlen(&p[0] + 1));
	return 0;
}

解析略

6        5        报错        报错        随机值        随机值        随机值

2.8

#include<stdio.h>
#include<string.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%zd\n", sizeof(a));//1
	printf("%zd\n", sizeof(a[0][0]));//2
	printf("%zd\n", sizeof(a[0]));//3
	printf("%zd\n", sizeof(a[0] + 1));//4
	printf("%zd\n", sizeof(*(a[0] + 1)));//5
	printf("%zd\n", sizeof(a + 1));//6
	printf("%zd\n", sizeof(*(a + 1)));//7
	printf("%zd\n", sizeof(&a[0] + 1));//8
	printf("%zd\n", sizeof(*(&a[0] + 1)));//9
	printf("%zd\n", sizeof(*a));//10
	printf("%zd\n", sizeof(a[3]));//11
	return 0;
}
2.8.1sizeof(a)

a是数组名,单独放在sizeof内部代表整个数组,该数组总共12个int类型元素故占48字节

返回         48

2.8.2sizeof(a[0][0])

a[0][0]代表首元素,为int类型,占4字节

返回        4

2.8.3sizeof(a[0])

a[0]也是一个数组名,单独放在sizeof内部代表整个数组,有三个元素,每个元素是4个整形组成的数组

返回        16

2.8.4sizeof(a[0]+1)

a[0]为数组名,此处代表首元素地址,+1后跳过一个元素,为指向第一个一维数组的第二个元素的指针

返回        4/8

2.8.5sizeof(*(a[0] + 1))

(a[0] + 1)为指向第一个一维数组的第二个元素的指针,解引用后为第二个元素

返回        4

2.8.6sizeof(a + 1)

a为首元素地址,即第一个一维数组的地址,+1跳过一个一维数组,是指向第二个一维数组的指针

返回        4/8

2.8.7sizeof(*(a + 1))

接着上题,解引用后代表第二个一维数组。

返回        16

2.8.8sizeof(&a[0] + 1))

&a[0]取出第一个一维数组的地址+1。是指向第二个一维数组的指针

返回        4/8

2.8.9sizeof(*(&a[0] + 1))

接上题,解引用后代表第二个一维数组。

返回        16

2.8.10sizeof(*a)

a为首元素地址,即第一个一维数组的地址,解引用代表第一个一维数组

返回        16

2.8.11sizeof(a[3])

a[3]是是数组名,含有4个int,越界,但不会去具体执行。

返回        16

3面试题

3.1

#include <stdio.h>
int main()
{
 int a[5] = { 1, 2, 3, 4, 5 };
 int *ptr = (int *)(&a + 1);
 printf( "%d,%d", *(a + 1), *(ptr - 1));
 return 0;
}

a为首元素地址(a+1)代表第二个元素地址,解引用后得2

&a代表整个数组地址,+1跳过这个数组,故ptr指向数组的后面,ptr-1表示上一个元素的地址,即5的地址

返回        2        5

3.2

#include <stdio.h>
int main()
{
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0;
}

(0,1)是逗号表达式,代表1故a中放的元素为{1,3,5,0,0,0},p是a[0],p[0]也就是a[0][0]

为该数组首元素

返回         1

3.3

#include<stdio.h>
int main()
{
 int a[5][5];
 int(*p)[4];
 p = a;
 printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
 return 0;
}//假设是x86

p是指向一个有四个整形的数组的指针,一个a有5个含有5个整形元素的数组。让p指向a的首元素 

&p[4][2]==a[0]+4*4+2

&a[4][2]==a[0]+4*5+2

相减为-4,

二进制源码10000000 00000000 00000000 00000100

反码           111111111 111111111 111111111  111111011

补码           111111111 111111111 111111111 111111100

以%p打印0xFF  FF FF FC

返回        0xFF  FF FF FC        -4

3.4

#include <stdio.h>
int main()
{
 int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 int *ptr1 = (int *)(&aa + 1);
 int *ptr2 = (int *)(*(aa + 1));
 printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
 return 0;
}

&aa代表整个数组,+1跳过这个这数组,故ptr1指向数组后面那个位置,-1再解引用返回末端元素

aa代表首元素地址,+1指向第二个元素,即第二个一维数组,-1再解引用返回第一个一维数组末端元素

返回        5        10

3.5

#include <stdio.h>
int main()
{
 char *a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;
 printf("%s\n", *pa);
 return 0;
}

a数组里放着三个char*类型指针,pa指向a的首元素地址,+1指向第二个元素地址,

返回        at

3.6最后一题!!!!

#include <stdio.h>
int main()
{
 char *c[] = {"ENTER","NEW","POINT","FIRST"};
 char**cp[] = {c+3,c+2,c+1,c};
 char***cpp = cp;
 printf("%s\n", **++cpp);
 printf("%s\n", *--*++cpp+3);
 printf("%s\n", *cpp[-2]+3);
 printf("%s\n", cpp[-1][-1]+1);
 return 0;
}

++cpp指向cp的第二个元素,两次解引用,返回POINT

再++cpp指向cp第三个元素,解引用后--,c+1这个元素变为c解引用得c数组首元素地址,+3后从第四个元素开始打印,返回ER

cpp[-2]访问cp的第一个元素,解引用后+3得ST

cpp[-1][-1]指向NEW,+1返回EW。

返回        POINT ER ST EW

终于写完了,同志们再见

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值