1、 字符指针
常见的字符指针 在指针的类型中我们知道有一种指针类型为字符指针 char* ;一般使用为:
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
不可修改的字符指针
int main()
{
char* pstr ="hello";
printf("%s\n", pstr);
printf("%c",*pstr);
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是两个独立的数组,开辟了两块独立的空间,所以str1和str2地址不同,str3和str4都指向同一个常量字符串,因为常量字符串不能被修改,又str3和str4都保存的字符串的首地址,即都指向同一位置。
图片解析:
2、指针数组
int arr[10];
char s[10];
int *p[10];
char*p[10];
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]);
}
printf("\n");
}
}
图片解析:
常量字符串数组
int main()
{
const char *arr[3]={"asdc","bds","cbsd"};
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 *p1[10];
int (*p2)[10];
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]);
printf("%d",(*(parr+0))[i]);
printf("%d",(*parr)[i]);
}
}
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);
}
分析一些数组和指针的问题:
int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];
int(*)[5]
4、数组参数、指针参数
我们在写程序的过程中,自定义函数的使用是必不可少的,既然有函数的使用,那么一定会有函数传参的过程,下面让我们来研究一下数组和指针在传参过程中的问题: 一维数组传参
#include <stdio.h>
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int arr[100])
{}
void test(int *arr)
{}
void test2(int *arr[20])
{}
void test2(int *arr[])
{}
void test2(int **arr)
{}
int main()
{
int arr[10] = {0};
int *arr2[20] = {0};
test(arr);
test2(arr2);
}
解析:因为传参不会真实的创建数组,所以[]里的数值可以省略,数组也可为任意值,但是任意值的写法容易产生歧义,所以不建议。 二维数组传参
void test(int arr[3][5])
{}
void test(int arr[][])
{}
void test(int arr[3][])
{}
void test(int arr[][5])
{}
void test(int *arr)
{}
void test(int* arr[5])
{}
void test(int (*arr)[5])
{}
void test(int **arr)
{}
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]);
print(p, sz);
return 0;
}
反向思维:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
void test1(int *p)
{}
void test2(char* p)
{}
二级指针传参 当函数的参数为二级指针的时候,可以接收什么参数?如下所示:
#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)
ret=(*pf)(4,5);
}
两段高阶代码:
(*(void (*)())0)();
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)={Add,Sub,Mul,Div};
}
函数指针数组的用途:转移表
void menu()
{
printf( "*************************\n");
printf( " 1:Add 2:Sub \n" );
printf( " 3:Mul 4:Div \n" );
printf( "*************************\n");
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
do
{
menu();
scanf( "%d", &input);
switch (input)
{
case 1:
printf( "输入操作数:" );
scanf( "%d %d", &x, &y);
ret = add(x, y);
printf( "ret = %d\n", ret);
break;
case 2:
printf( "输入操作数:" );
scanf( "%d %d", &x, &y);
ret = sub(x, y);
printf( "ret = %d\n", ret);
break;
case 3:
printf( "输入操作数:" );
scanf( "%d %d", &x, &y);
ret = mul(x, y);
printf( "ret = %d\n", ret);
break;
case 4:
printf( "输入操作数:" );
scanf( "%d %d", &x, &y);
ret = div(x, y);
printf( "ret = %d\n", ret);
break;
case 0:
printf("退出程序\n");
breark;
default:
printf( "选择错误\n" );
break;
}
} while (input);
return 0;
}
int main()
{
int x,y;
int input=0;
do
{
menu();
printf("请选择>");
scanf("%d",&input);
int (*pfArr[4])(int,int)={Add,Sub,Mul,Div};
if(input==0)
{
printf("退出计算器");
}
else if(input>=1&&input<=4)
{
printf("请输入两个操作数:>");
scanf("%d %d",&x,&y);
ret=pfArr[input](x,y);
printf("%d\n",ret);
}
}while(input);
return 0;
}
void Calc(int(*pf)(int,int))
{
int x=0;
int y=0;
int ret=0;
printf("请输入两个操作数>");
scanf("%d %d",&x,&y);
printf("%d",ret);
}
int main()
{
int input;
do
{
menu();
printf("请选择");
scanf("%d",&input);
switch (input)
{
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div)
break;
case 0:
printf("退出程序\n");
breark;
default:
printf( "选择错误\n" );
break;
}while(input);
return 0;
}
7、指向函数指针数组的指针
指向函数指针数组的指针是一个指针指针指向一个数组,数组的元素都是 函数指针。
int arr;
int (*p)[10];=&arr;
int *arr[10];
int* (*p)[10]=&arr;
int Add(int x,int y)
{
}
int (*pf)(int,int)=Add;
int (*pfArr[5])(int,int);
int (*(*ppfArr)[5])(int,int)ppfArr=&pfArr
图片解析:
|