博客
关于我
C语言指针比较高级的用法及指针数组面试题详解
阅读量:167 次
发布时间:2019-02-27

本文共 5074 字,大约阅读时间需要 16 分钟。

指针基础知识:

一、字符指针

字符指针有以下两种使用方法:

1.字符指针“存储”单个字符

char c = 'a';

char*  pc = &c;

*pc = 'a';

2.字符指针“存储”字符串

char* str = "hello world";

printf("%s\n",str);//打印结果:hello world

我们知道,当指针“存储”单个字符时,实际上指针存储的是该字符的地址,当对该字符指针进行解引用操作时直接访问该地址即可。那么,指针“存储”字符串是怎么存储的呢?

首先,我们知道指针的大小只有四个字节的空间,而且指针存储的是变量的地址,因此指针不可能真正的“存储”一个字符串。那么指针到底是如何存储字符串的呢?

实际上,指针存储字符串时存储的是字符串首元素的地址。在访问该字符串时,先通过指针找到首元素的地址,在根据首元素的地址访问字符串中的元素,直到遇到结束标志符‘\0’停止访问。

判断下面输出语句的输出结果:

这里str3str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域, 当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始 化不同的数组的时候就会开辟出不同的内存块。所以str1str2不同,str3str4不同。

二、数组指针

数组指针是指指向数组的指针。数组指针与其他类型指针一样,每+1加类型个字节(例如int型加一加四个字节,char型加一加一个字节,数组指针每加一加数组大小个字节)。

数组指针的定义:

char (*p)[10];

由于[]的优先级高于*的优先级,所以要给*p加上括弧变成(*p)表明p是一个指针类型。而后面的[10]说明的是该类指针是一个含有10个char型变量的数组指针。

 辨析数组的地址和数组首元素的地址:

有以下数组

int a[10];

a和&a各表示什么呢?哪一个是数组的地址,那一个是数组首元素的地址?

很明显,a是数组首元素的地址,&是数组的地址 。

从图中我们可以看出,a的值和&a的值相等,而a+1的值比&a+1的值小40(10个整型的大小,刚好是该数组a的大小)。所以,可以得出结论:数组的地址和数组首元素的地址的值是相等的,但是数组的地址+1加的是整个数组,首元素的地址+1加的是一个元素的大小。

三、指针数组

指针数组是指存储指针变量的数组,指针数组的定义如下:

int* arr1[10]; //整形指针的数组

char *arr2[4]; //一级字符指针的数组

char **arr3[5];//二级字符指针的数组

四、数组传参和指针传参

一维数组传参

一位数组的传参有以下几种方式:

int main()

{

int arr[10]={0};

test(arr);

}

void test(int arr[]){}//数组传参用数组接受肯定是可以的

void test(int* arr){}//数组传参传的时首元素的地址,所以也可以用指针来接受

判断下列一位数组传参是否正确:

int main()

{

int*arr[10]={0};

test(arr);

}

void test(int*arr[]){}//正确

void test(int**arr){}//正确;指针数组存储的是地址,传地址的地址用二级指针来接受也是没有问题的。

二维数组传参

规定,二维数组传参时数组的行数可以省略而列数不可以省略。所以,有以下传参方式:

void test(int arr[3][5])

void test(int arr[][5])

void test(int arr[3][])//这种省略列数的是不可行的

那么,下面这写二位数组的传参方式是否正确呢?

 
void
test
(
int *
arr
)
//二维数组的数组名指向的数组的首元素的地址,而二维数组的首元素是一个一维数组,所以应该用数组指针来接收
{}
void
test
(
int*
arr
[
5
])
//这里的参数是一个指针数组,因此错误
{}
void
test
(
int
(
*
arr
)[
5
])
//正确
{}
void
test
(
int **
arr
)
//错误,二维数组的数组名是数组指针不是二级指针
{}
int main()
{
int arr[3][5];
test(arr);
}
 

一级指针传参

一级指针传参有下面两种方式:

int main()

{

int a = 1;

int*  b = 'c';

test(&a);//传变量的地址

test(b);//传指针类型的变量

}

void test(int*a){}

二级指针传参

二级指针传参有以下几种方式:

int main()

{

char c = 'b';

char*pc = &c;

char**ppc = &pc;

char* arr[10];

test(&pc);//传一级指针的地址

test(ppc);//传二级指针变量

test(arr);//传指针数组的数组名

return 0;

}

void test(char** p){}

无、函数指针

函数指针就是指指向函数的指针。例如:void  test(){}对函数名test取地址(&test)就是一个函数指针,那么函数指针如何定义呢?

函数指针的定义

void (*pfun)();//变量pfun就是一个函数指针

函数指针的使用---改进的冒泡排序

冒泡排序的算法我们都很熟悉,依次遍历一组数据,每一次遍历让最小(最大)的数遍历到数组的开头,经过n-1次的遍历将数组变成一个降序(升序)的数组。那么我们有时可能既要对一组数进行升序排序又要进行降序排序,这样的话我们就要写两个函数依次进行升序和降序,但是,冒泡排序升序和降序程序大多数代码都是相同的,如果写两个代码的复用率就会大大降低,此时我们就可以采用函数指针来实现这个要求。代码如下:

void PopSort(int* nums,int numsSize,int(*p)(int,int)){	int i = 0,j;	int mid = 0;	for (j = 0; j < numsSize - 1;j++)	for (i = 0; i < numsSize - 1;i++)	if (p(nums[i],nums[i+1]))	{		mid = nums[i];		nums[i] = nums[i+1];		nums[i + 1] = mid;	}}int GreaterPopSort(int x,int y){	return x > y ? 1 : 0;}int LessPopSort(int x, int y){	return x < y ? 1 : 0;}int main(){	int i = 0;	int nums[] = {1,5,6,3,2,8,9,4,7};	//升序	PopSort(nums, 9, &GreaterPopSort);	for (i = 0; i<9; i++)		printf("%2d", nums[i]);	printf("\n");	//降序	PopSort(nums, 9, &LessPopSort);	for (i = 0; i<9; i++)		printf("%2d", nums[i]);	printf("\n");	return 0;}

运行结果如下:

六、 函数指针数组

函数指针数组是存放函数指针的数组。定义如下:

int (*prt[10])();//表示数组ptr含有十个元素,每个元素都是一个int(*)()的指针

七、 指向函数指针数组的指针

指向函数指针数组的指针是一个指针,这个指针存储的是一个数组的地址,这个数组存的类型时函数指针类型。定义如下:

void (*(*ppfunArr)[10])(const char*)

八、回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一 个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该 函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或 条件进行响应。

例如:上面我们讲过的函数指针解决冒泡排序就是一个回调函数的应用。当我们把GreaterPopSort或者LessPopSort的地址传递给PopSort函数时,PopSort在执行到相应地方时就会去调用这两个函数。

判断下列输出语句的输出结果:

part1:

part2:

part3:

part4:

:

part5

判断下列程序运行结果:

程序1:

int
main
()
{
   
int
a
[
5
]
=
{
1
,
2
,
3
,
4
,
5
};
   
int *
ptr
=
(
int *
)(
&
a
+
1
);
   
printf
(
"%d,%d"
,
*
(
a
+
1
),
*
(
ptr
-
1
));
  //2,5;*(a+1)=a[1]=2,*(ptr-1)=a[4]=5;
   
return
0
;
}
//
程序的结果是什么?

程序2:

程序3

int
main
()
{
   
int
a
[
4
]
=
{
1
,
2
,
3
,
4
};
   
int *
ptr1
=
(
int *
)(
&
a
+
1
);//数组最后一个元素的下一个位置
   
int *
ptr2
=
(
int *
)((
int
)
a
+
1
);
   
printf
(
"%x,%x"
,
ptr1
[
-
1
],
*
ptr2
);//4,2000000
   
return
0
;
}

程序4

#include <stdio.h>
int
main
()
{
   
int
a
[
3
][
2
]
=
{ (
0
,
1
), (
2
,
3
), (
4
,
5
) };
   
int *
p
;
   
p
=
a
[
0
];//二维数组的第一行
   
printf
(
"%d"
,
p
[
0
]);//1,逗号表达式的结果为最后一个值
return
0
;
}

程序5

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
]);//FFFFFFFC,-4
   
return
0
;
}

程序6

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
));//10,5
   
return
0
;
}

程序7

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

程序8

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
;
}
//结果
POINT
ER
ST
EW
 

转载地址:http://nzub.baihongyu.com/

你可能感兴趣的文章
multiprocessor(中)
查看>>
mysql CPU使用率过高的一次处理经历
查看>>
Multisim中555定时器使用技巧
查看>>
MySQL CRUD 数据表基础操作实战
查看>>
multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
查看>>
mysql csv import meets charset
查看>>
multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
查看>>
MySQL DBA 数据库优化策略
查看>>
multi_index_container
查看>>
MySQL DBA 进阶知识详解
查看>>
Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
查看>>
Mysql DBA 高级运维学习之路-DQL语句之select知识讲解
查看>>
mysql deadlock found when trying to get lock暴力解决
查看>>
MuseTalk如何生成高质量视频(使用技巧)
查看>>
mutiplemap 总结
查看>>
MySQL DELETE 表别名问题
查看>>
MySQL Error Handling in Stored Procedures---转载
查看>>
MVC 区域功能
查看>>
MySQL FEDERATED 提示
查看>>
mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
查看>>