目录
字符指针;
字符串的返回值是第一个元素第地址;
代码1:
int main()
{
char arr[] = "abcdef";//"abcdef"字符串返回的首元素的地址;
const char* a = "abcdef";//a接受的是字符串首元素的地址;
printf("%s\n", arr);//打印字符串的要给一个地址,从这个地址开始打印一直到\0;
printf("%c\n", *arr);
printf("%s\n", a);
printf("%c\n", *a);
return 0;
}
代码1分析:字符串返回的是首元素的地址,当数组名在sizeof后面或者&后面代表的是整个数组,在其他时候,代表的是首元素地址;printf打印字符串的要给一个地址,从这个地址开始打印一直到\0;*arr是第一个字符;a是字符串第一个元素的地址;*a是字符串第一个元素;
运行结果:
代码2:
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";//str2、str1可以改变;
const char* str3 = "hello bit.";//*str3内容不能改变;//常量字符串不允许修改,所以只要建立一个一样不可修改的字符串,只会在同一个内存,同一个地址;
const char* str4 = "hello bit.";//*str4内容不能改变;
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;
}
代码2分析:str1和str2是两个数组,数组的操作方式是将右边常量字符串的内容拷贝进来,所以他们是两个空间,只是内容相同,所以str1 != str2。而str3和str4是两个指针,编译器在处理的时候,会将相同的常量字符串做成同一个地址,所以,str3和str4指向的是同一个常量字符串,所以str3 == str4;
运行结果:
指针数组(存放指针的数组);
模拟二维数组的实现;
代码:
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,4,5 };
int arr3[] = { 1,2,3,4,5 };
int* arr[] = { arr1,arr2,arr3 };
int i = 0;
int j = 0;
for (i = 0;i < 3;i++)
{
for (j = 0;j < 5;j++)
{
///*printf("%d ", *(arr[i]+j));*/
//printf("%d ", arr[i][j]);//先遍历i,在遍历j
printf("%d ", *(*(arr+i)+j));
}
printf("\n");
}
return 0;
}
代码分析:因为arr1 arr2 arr3都是各个数组首元素的地址,都是int*类型,所以可以把他们存在int*[]类型的数组里;这样,arr就是arr1的地址,arr+1就是arr2的地址;这里写了三种对数组里的元素调用的代码;第一种就是可以把它理解成二维数组,i代表arri,j代表各个数组里元素的下标;第二周第三种都是基于一个式子:arr[i]==*(arr+i);
运行结果:
数组指针:指向数组变量的指针;
数组指针和数组名的区别;
代码:
int main()
{
int arr[10] = { 0 };
int (*x)[10] = &arr;//x是指针名,*表示指针 ,int[10]是所指向的内容;
printf("%p\n", arr);//int*
printf("%p\n", &arr[0]);
printf("%p\n", &arr);
printf("%p\n", arr+1);//int*
printf("%p\n", &arr[0]+1);
printf("%p\n", &arr+1);//整个数组地址;int[10]*(int(*)[10]);指向的是整个数组;
//指针加1跳过的大小是指针指向类型的大小;
return 0;
}
代码分析:当数组名在sizeof后面或者&后面的时候,代表的是整个数组;第一行的数组名代表数组第一个元素的地址;第二行:数组第一个元素的地址;第三行:整个数组的地址;前三行的数应该是一样的,因为整个数组的地址==数组第一个元素的地址;第四行:arr还是第一个元素的地址,加1,成为第二个元素的地址;第五行和第四行一样;第六行:整个数组的地址加1,跨越了一个数组;
运行结果:
数组指针访问数组里的元素;
代码:
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int (*p)[10]=&arr;
for (i = 0;i < sz;i++)
{
/*printf("%d ", *((*p)+i));*///(*p)得出来的是arr;可以加减得到其他地址再解引用,也可以当成数组使用;
printf("%d ", (*p) [i]);
}
return 0;
}
代码分析:p是整个数组的指针;指向arr,解引用得到arr,再+i解引用或者[i]就可以访问到arr里面的元素;
运行结果:
数组指针一般在二维数组使用比较方便;
代码:
void shuzu(int(*p)[5], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
printf("%d ", p[i][j]);//(*p)+i得到是第i行数组的数组名;
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
shuzu(arr, 3, 5);///这里得arr是数组首行数组的地址;
}
代码分析:二维数组的数组名和一维数组差不多一样,除了sizeof 和 &,其他时候都表示第一个元素的地址;不同的是二维数组的第一个元素是第一行数组;所以,shuzu函数里的arr是第一行数组的地址,类型是int(*)[5];传到数组里;对arr进行加减解引用或者当数组加下标可以得到其他行的地址,再进行一次解引用就可以访问到每行数组里的元素;
运行结果:
函数指针(指向函数的指针);
函数名是地址,取地址函数名也是函数地址;所以传的时候&可以省略;
代码:
int add(int x, int y)
{
return x + y;
}
int main()
{
int (*p)(int, int) = &add;//*表示指针,int (int x,int y) //p是函数指针变量;返回类型(*p)(参数1类型,参数2类型)
//返回类型 (参数1类型,参数2类型)这是p指向的函数类型;
printf("%p\n", p);
printf("%p\n", &add);
printf("%p\n", add);//函数名是地址,取地址函数名也是函数地址;
return 0;
}
运行结果:
函数指针的类型;
函数指针的类型:返回类型(*变量名)(变量1类型,变量2类型.......);
代码1:
int add(int x, int y)
{
return x + y;
}
int main()
{
int (*pa)(int ,int ) = add;//注意括号不要省略;// int(*)(int,int)是pa的类型;
//void (*pc)(char*, int[]) = test;//test和&test都是函数地址;
//void (*pb)(char*, int*) = &test;
//printf("%p\n", pa);
//printf("%p\n", pb);
int back = (*pa)(10, 10);//解引用找到函数输入参数;
int back1 = pa(10, 10);//pa相当于add,加*相当于告诉你这个是指针;
printf("%d\n", back);
printf("%d\n", back1);
return 0;
}
代码分析:pa是函数指针类型的变量;通过函数指针调用函数的时候可以解引用,也可以不解引用,都可以直接调用函数;
运行结果:
代码2:
int main()
{
(*(void (*)())0)();//1.把0强制转换为void (*)()函数指针类型,再解引用找到函数并调用(其实不用解引用,地址就可以表示函数);
}
代码2分析:把0强制转换为void (*)()函数指针类型,再解引用找到函数并调用(其实不用解引用,地址就可以表示函数);
对类型的重命名及使用;
代码:
int main()
{
//void (*signal(int, void(*)(int)))(int);//signal是函数名,signal有一个int型的参数,一个void(*)(int)型的参数,返回类型是
//去掉函数名剩下的,即void(*)(int)型是函数的返回类型;
dd signal(int, dd); //重命名后的函数;
}
对类型的重命名;
typedef unsigned int uint;
typedef void(*dd)(int);//表示对指向void(int)函数的指针重命名为dd,注意,对指针类型的重命名时,新名字要写在*后面;
typedef int(*a)[10];//表示对指向int[10]的数组指针重命名为a;
代码分析:void (*signal(int, void(*)(int)))(int);signal是函数名,signal有一个int型的参数,一个void(*)(int)型的参数,返回类型是去掉函数名剩下的,即void(*)(int)型是函数的返回类型;这样写不容易直接看出返回类型和参数类型;现在把void(*)(int)类型重命名成dd;注意,对指针类型的重命名时,新名字要写在*后面;对数组指针重命名时也要遵从这个规则;
函数指针数组及其应用:
存放函数指针的数组;数组的每个元素都是函数指针类型;
应用:只有两个操作数的计算器,可以实现加减乘除的运算;
代码:
int jia(int x, int y)
{
return x + y;
}
int jian(int x, int y)
{
return x - y;
}
int cheng(int x, int y)
{
return x * y;
}
int chu(int x, int y)
{
return x/y;
}
void menu()
{
printf("******0.exit ***********\n");
printf("******1.jia ***********\n");
printf("******2.jian ***********\n");
printf("******3.cheng***********\n");
printf("******4.chu ***********\n");
}
int main()
{
/*int(*add[4])(int, int) = { jia,jian,cheng,chu };*///add[4]是函数指针数组;
int(*arr[5])(int, int) = { NULL,jia,jian,cheng,chu };//函数名就是函数的地址;jia=*jia=arr[1]=*arr[1]
int n = 0;
do{
int x = 0;
int y = 0;
menu();
printf("请输入:> ");
scanf("%d", &n);
if (n>=1&&n<=4)
{
printf("%请输入操作数:>");
scanf("%d %d", &x, &y);
int ret = arr[n](x, y);
printf("%d\n", ret);
}
else if (n > 4||n < 0)
{
printf("请重新输入\n");
}
else
{
printf("退出游戏\n");
}
} while (n);
return 0;
}
代码分析:建立一个函数指针数组,在里面根据需要放入函数指针(函数名),进入dowhile循环,进入菜单栏,根据需要输入数,根据数值进入if语句;如果数据合适,再根据需要输入操作数,根据输入数值调用数组arr里的元素,因为每个元素都是函数的指针,所以可以直接调用函数;
运行结果:
函数指针数组指针;
函数指针数组指针是指向一个数组,数组里的元素是函数指针;
代码:
int main()
{
int(*arr[5])(int, int);
int(*(*p)[5])(int, int) = &arr;//最里面的星表示p是指针,[5]表示指向的是数组;数组的元素类型是int(*)(int, int)
return 0;
}
代码分析:arr是数组,数组里5个元素,元素类型是(int(*)(int,int));p是指针,指向一个有五个元素的数组,元素类型是int(*)(int,int);