搞定C语言指针,指针超详细讲解,及指针面试题
Posted Jiawen_captial
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搞定C语言指针,指针超详细讲解,及指针面试题相关的知识,希望对你有一定的参考价值。
C语言指针进阶
1、 字符指针
常见的字符指针
在指针的类型中我们知道有一种指针类型为字符指针 char* ;一般使用为:
int main()
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
不可修改的字符指针
int main()
char* pstr ="hello";
//一定切记不是把hello放到pstr里面去
printf("%s\\n", pstr);
//直接使用地址打印字符串,不用解引用
printf("%c",*pstr);//打印h
//证明里面放的是首元素的地址
//常量字符串不允许被修改,用const加以修饰
const char* pstr ="hello";
return 0;
代码 char* pstr = “hello”; 特别容易让同学以为是把字符串 hello bit 放到字符指针 pstr 里了,但是/本质是把字符串 hello 首字符的地址放到了pstr中。
字符指针的例题:
#include <stdio.h>
int main()
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char *str3 = "hello bit.";
char *str4 = "hello bit.";
if(str1 ==str2)
printf("str1 and str2 are same\\n");
else
printf("str1 and str2 are not same\\n");
if(str3 ==str4)
printf("str3 and str4 are same\\n");
else
printf("str3 and str4 are not same\\n");
return 0;
//str1不等于str2,str3等于str4
解析:str1和str2是两个独立的数组,开辟了两块独立的空间,所以str1和str2地址不同,str3和str4都指向同一个常量字符串,因为常量字符串不能被修改,又str3和str4都保存的字符串的首地址,即都指向同一位置。
图片解析:
2、指针数组
int arr[10];//整型数组-存放整型的数组
char s[10];//字符数组-存放字符的数组
//指针数组-存放指针的数组
int *p[10];//存放int *的数组
char*p[10];//存放char*的数组
int main()
int arr1[]=1,3,4,5;
int arr2[]=2,6,5,7;
int arr3[]=1,9,6,4;
int *p[]=arr1,arr2,arr3;
int i=0;
for(i=0;i<3;i++)
int j=0;
for(j=0;j<5;j++)
printf("%d",p[i][j]);
//抽象理解为二维数组,依靠p[i][j]==*(p[i]+j)
printf("\\n");
图片解析:
常量字符串数组
int main()
const char *arr[3]="asdc","bds","cbsd";
//将a,b,c等首元素的地址存入arr
int i=0;
for(i=0;i<3;i++)
printf("%s\\n",arr[i]);
return 0;
补充:关于printf打印字符串,只要提供起始地址就能进行打印,但是只针对打印字符串。另外指针数组的数组名是一级指针,要用二级指针存储。
图片解析:
3、数组指针
数组指针是指针,一种指向数组的指针。
int main()
int arr[10];
int *p=arr;//取出数组首元素的地址,放到整型指针中
int (*parr)[10]=&arr;//取出的是数组的地址,应该存放到数组指针中
//int (*)[10]为指针parr的类型
//首先parr为数组,指向大小为10的数组,数组的的元素为int类型
int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?
p1为指针数组,p2为数组指针
int (*p)[10];
解释:p先和*结合,说明p是一个指针变量,然后接着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
这里要注意:[]的优先级要高于号的,所以必须加上()来保证p先和结合。
使用数组指针的一种遍历
这种写法是为了让大家加强对指针的理解,在实际的操作过程中,这样写只会加强代码的复杂性。
void Print(int(*parr)[10],int sz)
int i=0;
for(i=0;i<sz;i++)
printf("%d",parr[0][i]);
//[0]找到了这个数组的第一行,[i]来找一行的元素
printf("%d",(*(parr+0))[i]);
//将其看成一个只有一行的二维数组
printf("%d",(*parr)[i]);
//(*parr)相当于parr指向的数组的数组名
int mian()
int arr[10]=1,2,3,4,5,6,7,8,9,10;
int sz=sizeof(arr)/sizeof(arr[0]);
Print(&arr,sz);
return 0;
对于数组指针,在使用的过程中一定要慎重,随意的使用会造成复杂的的升高和难以理解,如上述代码,下面来看一下数组指针的优点使用,推荐在二维数组及其以上使用。
参数部分也是二维数组
Print1(int arr[3][5],int r,int c)
int i=0;
for(i=0;i<r;i++)
int j=0;
for(j=0;j<c;j++)
printf("%d",arr[i][j]);
printf("\\n")
void Print2(int (*p)[5],int r,int c)
int i=0;
for(i=0;i<r;i++)
int j=0;
for(j=0;j<c;j++)
printf("%d",*(*(p+i)+j));
printf("%d",p[i][j]);
//两种方法都能实现打印,细细体会两种方法的实现
int main()
int arr[3][5]=1,2,3,4,5,2,3,4,5,6,3,4,5,6,7;
//二维数组传参
Print1(arr,3,5);
Print2(arr,3,5);//arr是数组名,数组名是首元素的地址
//把二维数组的每一行看成一个元素,元素为一行的一维数组的数组
//数组名是首元素的地址,二维数组的数组名是第一行的地址
分析一些数组和指针的问题:
int arr[5];
//arr和[]结合说明arr为数组,int说明为整型数组
int *parr1[10];
//parr1是一个数组,10个元素,每个元素是int*的
//所以parr1是一个存放指针的数组
int (*parr2)[10];
//parr2是一个数组指针,该指针指向的数组有10个元素,每个元素是int类型的
int (*parr3[10])[5];
int(*)[5]
//parr3是个数组,数组有10个元素
//每个元素是一个数组指针,该指针指向的数组有5个元素
//每个元素是int类型
4、数组参数、指针参数
我们在写程序的过程中,自定义函数的使用是必不可少的,既然有函数的使用,那么一定会有函数传参的过程,下面让我们来研究一下数组和指针在传参过程中的问题:
一维数组传参
#include <stdio.h>
void test(int arr[])//ok
void test(int arr[10])//ok
void test(int arr[100])//ok 虽然语法正确,但是不建议
void test(int *arr)//ok
void test2(int *arr[20])//ok
void test2(int *arr[])//ok
void test2(int **arr)//ok 接收一级指针的地址,使用二级指针
int main()
int arr[10] = 0;
int *arr2[20] = 0;
//20个元素每个元素都是int*的,首元素的地址为一个一级指针的地址
test(arr);
test2(arr2);
解析:因为传参不会真实的创建数组,所以[]里的数值可以省略,数组也可为任意值,但是任意值的写法容易产生歧义,所以不建议。
二维数组传参
void test(int arr[3][5])//ok
void test(int arr[][])//no
void test(int arr[3][])//no
void test(int arr[][5])//ok
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//no
void test(int* arr[5])//no
void test(int (*arr)[5])//ok
void test(int **arr)//no
int main()
int arr[3][5] = 0;
test(arr);//二维数组首元素的地址为第一行的地址
一级指针传参
#include <stdio.h>
void print(int *p, int sz)
int i = 0;
for(i=0; i<sz; i++)
printf("%d\\n", *(p+i));
int main()
int arr[10] = 1,2,3,4,5,6,7,8,9;
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
反向思维:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
void test1(int *p)
//test1函数能接收什么参数?
//1、整型变量的地址
//2、整型数组首元素的地址
//3、一级指针变量
void test2(char* p)
//test2函数能接收什么参数?
//1、字符变量的地址
//2、字符数组首元素的地址
//3、一级指针的变量
二级指针传参
当函数的参数为二级指针的时候,可以接收什么参数?如下所示:
#include <stdio.h>
void test(int** ptr)
printf("num = %d\\n", **ptr);
int main()
int n = 10;
int*p = &n;
int **pp = &p;
int *arr[5];
test(pp);
test(&p);
tset(arr);
return 0;
5、函数指针
先来看一段代码:
int Add(int x,int y)
return x+y;
int main()
printf("%p\\n",&Add);
printf("%p\\n",Add);
//两个一句打印的内容一样
//&函数名和函数名意义相同
上述代码说明函数是有地址的,那么存放函数地址的指针称为函数指针。
int Add(int x,int y)
return x+y;
int main()
printf("%p\\n",&Add);
printf("%p\\n",Add);
int (*pf)(int,int)=&Add;
int(*)(int,int)//函数指针的类型
//pf是用来存放函数地址的-pf就是函数指针变量
//pf与*结合说明pf是个指针,后面的括号说明函数的参数
//为int,int类型的,前面的int说明返回值为int类型
//利用函数指针调用函数
ret=(*pf)(4,5);
//或者ret=pf(4,5);
两段高阶代码:
//代码1
(*(void (*)())0)();
//代码是一次函数调用
//解析:
//1、代码中把0强制类型转换成为类型为void(*)()的一个函数的地址
//2、解引用0地址,就是去0地址处的这个函数,被调用的函数无参数,返回类型是void
//代码2
void (*signal(int , void(*)(int)))(int);
//这个代码是一次函数声明
//signal函数有两个参数,第一个是int类型,第二个是void(*)(int)的函数指针类型
//signal函数的返回值类型依然是:void(*)(int)的函数指针类型
//使用typedef简化
//typedef int s;s为int的别名,具有int的属性
//typedef void(*pf)(int);把void(*)(int)从新命名为pf,具有同等属性
//pf signal(int,pf);等价void (*signal(int , void(*)(int)))(int);
6、函数指针数组
函数指针数组-存放函数指针的数组
int main()
int (*pf1)(int,int)=Add;
int (*pf2)(int,int)=Sub;
int (*pf3)(int,int)=Mul;
int (*pf4)(int,int)=Div;
//对于同类型的函数指针单独存储,代码太过复杂,所以要使用函数指针数组
int (*pfArr[4])(int,int以上是关于搞定C语言指针,指针超详细讲解,及指针面试题的主要内容,如果未能解决你的问题,请参考以下文章