引言:
对指针知识进行简单的回顾,然后再完成笔试题。
目录
知识简单回顾
指针是什么
内存 ->内存的单元(1byte)->编号->地址
指针就是一个地址。
我们口头语说的指针一般指:指针变量
指针变量就是一个变量,就是一块内存空间,指针变量用来存放地址。
int main()
{
int a = 0;
int* pa = &a;
*pa = 20;
return 0;
}
指针变量的大小?
指针类型的意义
两件事情:
1.指针类型进行+1/-1的操作时,它会跳过几个字节。
2.进行解引用操作的时候,决定了解引用操作时候的权限,(访问多少个字节)
指针的运算
1。+-整数
2.指针-指针
3.指针的关系运算
指针数组
本质上就是数组,数组中存放的是指针(地址)。
arr 存放了三个元素,每个元素都是int*类型,也就是指针,那么arr就是指针数组。
int main()
{
int *pa;
int *pb;
int *pc;
int* arr = { pa,pb,pc };
return 0;
}
数组名是什么
1.数组名在大部分情况下表示数组首元素的地址,
但是有两个例外:
a)sizeof(数组名),表示的是整个数组的大小
b)&数组名,取出的是整个数组的地址
数组指针
&数组名,这里的parr ,存放的是数组的地址,parr为数组指针。
数组指针:int (*parr)[10],parr与*结合,代表parr为指针,[10]表示parr指向数组,数组中元素的类型是int。
指针数组:int* parr[10],没有括号,parr与[10]结合,表示parr为数组,数组中元素的类型是int*(整形指针)
数组指针类型的表示:int (*)[10];
int arr[10] = {1,2,3};
int (*parr)[10] = &arr;
函数指针
函数指针就是函数的地址,函数也有地址,我们可以通过函数的地址去使用函数。
函数的地址存放在函数指针变量中,
函数指针类型表示:
int (*)(int,int)
int (*pf)(int ,int),pf与*结合,表示pf是指针,指针指向的是(int , int)参数是两个整形的函数,函数的返回类型是int。
int Add(int x,int y)
{
return x + y;
}
int main()
{
int (*pf)(int ,int) = &Add;
int sum = (*pf)(2,3);
//Add 和 &函数名一样,Add也可以直接表示为地址,因此也可以写成这种形式
//int (*pf)(int ,int) = Add;
//Add传给了pf,pf 等同于 Add ,那么我们也可以这样写。
//int sum = pf(2.3)
return 0;
}
函数指针数组
存放函数指针的数组。
我们将函数指针数组命名为arr,arr数组的每个元素的类型是:int (*)(int,int)
int (*arr[4])(int,int) = {Add,Sub,Div,Mul};
回调函数
通过函数指针调用的函数就是回调函数。
这里的函数指针是pf,pf指向的函数是Add,通过pf调用Add,我们称Add为回调函数。
int Add(int x,int y)
{
return x + y;
}
int main()
{
int (*pf)(int ,int) = Add;
int sum = pf(2.3);
return 0;
}
笔试题
一维数组
题目:
以下打印的结果分别是什么?
int a[] = {1,2,3,4};
1|printf("%d\n",sizeof(a));
2|printf("%d\n",sizeof(a+0));
3|printf("%d\n",sizeof(*a));
4|printf("%d\n",sizeof(a+1));
5|printf("%d\n",sizeof(a[1]));
6|printf("%d\n",sizeof(&a));
7|printf("%d\n",sizeof(*&a));
8|printf("%d\n",sizeof(&a+1));
9|printf("%d\n",sizeof(&a[0]));
10|printf("%d\n",sizeof(&a[0]+1));
解析:
1.printf (" %d\n ", sizeof ( a ) ); 16
2.printf (" %d\n ", sizeof( a+0 ) ); 4 / 8
3.printf (" %d\n ", sizeof( *a ) ); 4
4.printf (" %d\n ", sizeof( a+1 ) ); 4 / 8
5.printf (" %d\n ", sizeof( a[1] ) ); 4
6.printf (" %d\n ", sizeof( &a ) ); 4 / 8
注意:首元素的地址和数组的地址虽然表现是同一个地址,但是它们的运算的结果是不一样的。
比如:&a+1和a+1,一个表示的是跳过了一个(4个整形元素的)数组的地址,一个表示的是数组第二个元素的地址
7.printf (" %d\n ", sizeof( *&a ) ); 16
8.printf (" %d\n ", sizeof( &a+1 ) ); 4 / 8
9.printf (" %d\n ", sizeof( &a[0] ) ); 4 / 8
10.printf (" %d\n ", sizeof( &a[0]+1 ) ); 4 / 8
总结:
1.数组名大多数表示首元素的地址,有两个例外:1.sizeof(数组名)2.&数组名。数组名表示的是整个数组 。
2.不同类型地址跳过的字节不一样,&a+1,&a表示的是整个数组,+1就会跳过一个数组的大小。&a[0]+1,&a[0]是数组第一个元素的地址,所以+1跳过的是一个元素的大小。
3.地址意义可能不同,但是地址的大小都是4 / 8个字节。
字符数组
题目1:
以下打印的结果是什么?
char arr[] = {'a','b','c','d','e','f'};
1|printf("%d\n",sizeof(arr));
2|printf("%d\n",sizeof(arr+0));
3|printf("%d\n",sizeof(*arr));
4|printf("%d\n",sizeof(arr[1]));
5|printf("%d\n",sizeof(&arr));
6|printf("%d\n",sizeof(&arr+1));
7|printf("%d\n",sizeof(&arr[0]+1));
解析:
1| printf (" %d\n " , sizeof ( arr ) ) 6
2|printf (" %d\n ", sizeof( arr+0 ) ) 4 / 8
3|printf (" %d\n ",sizeof ( *arr ) ) 1
4|printf (" %d\n ", sizeof( arr[1] ) ) 1
5|printf (" %d\n ", sizeof( &arr ) ) 4 / 8
6|printf (" %d\n ", sizeof( &arr+1 ) ) 4 / 8
7|printf (" %d\n ", sizeof( &arr[0]+1 ) ) 4 / 8
题目2:
以下的打印结果分别是什么?
char arr[] = {'a','b','c','d','e','f'};
1|printf("%d\n",strlen(arr));
2|printf("%d\n",strlen(arr+0));
3|printf("%d\n",strlen(*arr));
4|printf("%d\n",strlen(arr[1]));
5|printf("%d\n",strlen(&arr));
6|printf("%d\n",strlen(&arr+1));
7|printf("%d\n",strlen(&arr[0]+1));
解析:
strlen
用来求字符串长度的库函数,参数是地址,从参数传来的地址开始,直到有' \0 '停止。
1|printf (" %d\n ", strlen ( arr ) ) 随机值
2|printf (" %d\n ", strlen ( arr+0 ) ) 随机值
3|printf (" %d\n ", strlen ( *arr ) ) 访问冲突
4|printf (" %d\n ", strlen ( arr[1] ) ) 访问冲突
5|printf (" %d\n ", strlen ( &arr ) ) 随机值
6|printf (" %d\n ", strlen ( &arr+1 ) ) 随机值 - 6
7|printf (" %d\n ", strlen ( &arr[0]+1 ) ) 随机值 - 1
总结:
1.strlen(const char* str)传递的参数是地址,如果传递数值的话,就会产生访问冲突的问题。
2.strlen不管地址的类型,只管地址的位置,从地址的位置开始,逐个去数字符,直到遇到 \0 ,strlen就停止运行,求出字符串的长度。
题目3:
以下打印的结果是什么?
char arr[] = "abcdef";
1|printf("%d\n",sizeof(arr));
2|printf("%d\n",sizeof(arr+0));
3|printf("%d\n",sizeof(*arr));
4|printf("%d\n",sizeof(arr[1]));
5|printf("%d\n",sizeof(&arr));
6|printf("%d\n",sizeof(&arr+1));
7|printf("%d\n",sizeof(&arr[0]+1));
解析:
char arr[] = "abcdef",这个数组的元素为[ a b c d e f \0 ],一共7个元素,字符串默认以 \0 结尾。
1|printf (" %d\n ", sizeof ( arr ) ) 7
2|printf (" %d\n ", sizeof ( arr+0 ) ) 4 / 8
3|printf (" %d\n ", sizeof ( *arr ) ) 1
4|printf (" %d\n ", sizeof ( arr[1] ) ) 1
5|printf (" %d\n ", sizeof ( &arr ) ) 4 / 8
6|printf (" %d\n ", sizeof ( &arr+1 ) ) 4 / 8
7|printf (" %d\n ", sizeof ( &arr[0]+1 ) ) 4 / 8
总结:
1.不管地址的类型是什么,只要是地址,地址的大小就是4个字节或者8个字节。
2.字符串相当于普通的字符数组,但是字符串通常默认 \0 为结尾。
3.sizeof 只关注占用内存空间的大小,不在乎内存中放的是什么。
题目4:
以下打印的结果是什么?
char arr[] = "abcdef";
1|printf("%d\n",strlen(arr));
2|printf("%d\n",strlen(arr+0));
3|printf("%d\n",strlen(*arr));
4|printf("%d\n",strlen(arr[1]));
5|printf("%d\n",strlen(&arr));
6|printf("%d\n",strlen(&arr+1));
7|printf("%d\n",strlen(&arr[0]+1));
解析:
1|printf (" %d\n" , strlen ( arr ) ) 6
2|printf (" %d\n ", strlen ( arr+0 ) ) 6
3|printf (" %d\n ", strlen ( *arr ) ) 访问冲突
4|printf (" %d\n ", strlen ( arr[1] ) ) 访问冲突
5|printf (" %d\n ", strlen ( &arr ) ) 6
6|printf (" %d\n ", strlen ( &arr+1 ) ) 随机值
7|printf (" %d\n ", strlen ( &arr[0]+1 ) ) 5
总结:
1. strlen是求字符串长度的,关注的是字符串中的 \0 ,计算的是 \0 之前出现的字符的个数。
2.sizeof 只关注占用内存空间的大小,不在乎内存中放的是什么。
题目5:
char* p = "abcdef";
1|printf("%d\n",sizeof(p));
2|printf("%d\n",sizeof(p+1));
3|printf("%d\n",sizeof(*p));
4|printf("%d\n",sizeof(p[0]));
5|printf("%d\n",sizeof(&p));
6|printf("%d\n",sizeof(&p+1));
7|printf("%d\n",sizeof(&p[0]+1));
答案:
1|printf (" %d\n ", sizeof ( p ) ) 4 / 8
p是 指针变量,存放的是’a‘的地址。地址的大小为4个字节或者8个字节。
3|printf (" %d\n ", sizeof ( *p ) ) 1
4|printf (" %d\n ", sizeof ( p[0] ) ) 1
5|printf (" %d\n ", sizeof ( &p ) ) 随机值
6|printf (" %d\n ", sizeof ( &p+1 ) ) 4 / 8
7|printf (" %d\n ", sizeof ( &p[0]+1 ) ) 4 / 8
题目6:
char* p = "abcdef";
1|printf("%d\n",strlen(p));
2|printf("%d\n",strlen(p+1));
3|printf("%d\n",strlen(*p));
4|printf("%d\n",strlen(p[0]));
5|printf("%d\n",strlen(&p));
6|printf("%d\n",strlen(&p+1));
7|printf("%d\n",strlen(&p[0]+1));
答案:
1|printf (" %d\n ", strlen( p ) ) 6
2|printf (" %d\n ", strlen( p+1 ) ) 5
3|printf (" %d\n ", strlen ( *p ) ) 访问冲突
4|printf (" %d\n ", strlen ( p[0] ) ) 访问冲突
5|printf (" %d\n ", strlen ( &p ) ) 随机值
6|printf (" %d\n ", strlen( &p+1 ) ) 随机值 - 1
7|printf (" %d\n ", strlen ( &p[0]+1 ) ) 5