【C语言进阶】二、指针-创新互联
一、指针数组
我们提供的服务有:网站制作、成都网站设计、微信公众号开发、网站优化、网站认证、同安ssl等。为成百上千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的同安网站制作公司存放指针的数组
int* arr[10];
二、数组指针
指向数组的指针
int (*p)[10] 其中p是数组指针的名字
int (*) [10] 这个是类型(&arr 取出的类型)
三、数组参数和指针参数
一维数组传参,直接使用指针接收
void test(int *arr)
二维数组的传参,
void test(int arr[3][5]);
void test(int arr[][5]);//行可以省略,列不可以省略,但是不可以都省略
void test(int (*p)[5]);//形参写成指针的形式
注:
当函数的形参是二级指针时,不可以只把二维数组的数组名传入函数,因为二维数组的数组名是第一行的地址,需要用数组指针来接收。
四、函数指针
函数指针存储的是函数的地址,其中,例如,函数名是Add ,&Add 与 Add 意义一样;
int Add (int x,int y)
{
return x+y;
}
此函数的地址表达方式是: int (*pf)(int , int)=Add; pf 就是函数指针变量。
注:
a、int ret = (*pf) (2,3); 和 int ret = Add(2,3); 和 int ret = pf(2,3); 等价,其中第一个表达式中的 * 相当于摆设,无实际作用,但如果加了 * 千万不要忘了加括号,必须加括号!
例题:
下边的两行代码的意思
1 . ( *(void (*) () ) 0 ) ();
a、(void (*) () )是函数指针类型,是强制类型转换的作用;
b、(void (*) () ) 0 对0进行强制类型转换,意思就是认为0地址处放置着(void (*) () )类型的函数;
c、*(void (*) () ) 0 对此函数进行解引用
d、( *(void (*) () ) 0 ) () 调用该函数
2 . void(*signal (int , void ( * ) (int)) ) (int);
a、signal 先和括号结合,所以signal目前是一个函数
b、signal (int , void ( * ) (int)) 表示signal的第一个参数是 int ,第二个参数是void ( * ) (int) 是一个函数指针类型;
c、void(*signal (int , void ( * ) (int)) ) (int) 表示函数的返回类型是void(*) (int)
五、函数指针数组
例如有四个函数:
int (*pf1) (int ,int) = Add;
int (*pf1) (int ,int) = Sub;
int (*pf1) (int ,int) = Mul;
int (*pf1) (int ,int) = Div;
函数指针数组的表达方式
int (*pf[5]) (int ,int) = {0, Add, Sub, Mul, Div}; pf首先和 [4] 结合
六、指向函数指针数组的指针
函数指针 int (*pf) (int ,int ) = &Add;
函数指针数组 int (* pfarr[4]) (int , int);
指向函数中指针数组的指针 int (* (*p3)[4]) (int , int) = &pfarr;
七、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一 个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。void test()
{
printf("hehe\n");
}
void print_hehe(void (*p) ())
{
if(1)
{
p();
}
}
int main()
{
print_hehe(test);
return 0;
}
以上代码,没有调用函数 test(),将函数指针传给了 print_hehe 由此函数通过 if 条件和函数指针来调用函数,此时 test() 是回调函数。
用法:
#includevoid menu()
{
printf("##############################\n");
printf("##### 1.Add 2.Sub ####\n");
printf("##### 3.Mul 4.Div ####\n");
printf("##### 0.exit ####\n");
printf("##############################\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
void calc(int(*pf)(int, int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入2个操作数:>");
scanf("%d%d", &x, &y);
ret = pf(x, y);
printf("ret=%d\n", ret);
}
int main()
{
int input = 0;
int ret = 0;
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("退出!");
break;
default:
printf("选择错误!");
break;
}
} while (input);
return 0;
}
上边代码中 calc() 就是回调函数.
下边是 qsort 的使用,qsort是一个库函数,是基于快速排序算法实现的一个排序函数,qsort可以排序任意类型的数据。
void qsort (void* base, 待排序数组的起始位置
size_t num, 数组元素个数
size_t width, 一个元素的字节大小
int (*cmp)(const void* e1,const void* e2) 函数指针,cmp是比较函数,e1、 e2是待比较两个元素的地址。返回值是当e1
e2时,返回>0的数。cmp是自定义的比较函数。 )
#include#includeint cmp_int(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);
}
struct Stu
{
char name[20];
int age;
double score;
};
int cmp_stu_by_age(const void* e1,const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test1()
{
struct Stu arr[3] = { {"mike",20,55.5},{"lisa",30,88.0},{"kuka",50,90.0} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}
void test()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
}
int main()
{
test();
test1();
return 0;
}
注:
a、void* 类型的指针可以接收任意类型的指针;
指针与数组相关例题解析
例1、
int main()
{
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a))
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
return 0;
}
sizeof 计算对象所占内存的大小,单位是字节。
printf("%d\n",sizeof(a)) 16
printf("%d\n",sizeof(a+0)); 4/8 表示数组首元素的地址
printf("%d\n",sizeof(*a)); 4 表示第一个元素的大小
printf("%d\n",sizeof(a+1)); 4/8 第二个元素的地址的大小
printf("%d\n",sizeof(a[1])); 4 第二个元素的大小
printf("%d\n",sizeof(&a)); 4/8 数组的地址的大小
printf("%d\n",sizeof(*&a)); 16 计算整个数组的大小
printf("%d\n",sizeof(&a+1)); 4/8 计算指向数组后边数组处地址的大小
printf("%d\n",sizeof(&a[0])); 4/8 第一个元素地址的大小
printf("%d\n",sizeof(&a[0]+1)); 4/8 第二个元素地址的大小
例2、
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
return 0;
}
sizeof 计算对象所占内存的大小,单位是字节。
printf("%d\n", sizeof(arr)); 6
printf("%d\n", sizeof(arr+0)); 4/8
printf("%d\n", sizeof(*arr)); 1
printf("%d\n", sizeof(arr[1])); 1
printf("%d\n", sizeof(&arr)); 4/8
printf("%d\n", sizeof(&arr+1)); 4/8
printf("%d\n", sizeof(&arr[0]+1)); 4/8printf("%d\n", strlen(arr)); 随机值
printf("%d\n", strlen(arr+0)); 随机值
printf("%d\n", strlen(*arr)); err,此时*arr是首元素,首元素的值是97,可能会发生越界
printf("%d\n", strlen(arr[1])); err
printf("%d\n", strlen(&arr)); 随机值
printf("%d\n", strlen(&arr+1)); 随机值
printf("%d\n", strlen(&arr[0]+1)); 随机值
例3、
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
return 0;
}
sizeof 计算对象所占内存的大小,单位是字节。
printf("%d\n", sizeof(arr)); 7
printf("%d\n", sizeof(arr+0)); 4/8 数组首元素地址
printf("%d\n", sizeof(*arr)); 1 首元素
printf("%d\n", sizeof(arr[1])); 1
printf("%d\n", sizeof(&arr)); 4/8
printf("%d\n", sizeof(&arr+1)); 4/8
printf("%d\n", sizeof(&arr[0]+1)); 4/8printf("%d\n", strlen(arr)); 6
printf("%d\n", strlen(arr+0)); 6
printf("%d\n", strlen(*arr)); err
printf("%d\n", strlen(arr[1])); err
printf("%d\n", strlen(&arr)); 6
printf("%d\n", strlen(&arr+1)); 随机值
printf("%d\n", strlen(&arr[0]+1)); 5
例4、
int main()
{
char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));
return 0;
}
sizeof 计算对象所占内存的大小,单位是字节。
printf("%d\n", sizeof(p)); 4/8
printf("%d\n", sizeof(p+1)); 4/8
printf("%d\n", sizeof(*p)); 1
printf("%d\n", sizeof(p[0])); 1
printf("%d\n", sizeof(&p)); 4/8
printf("%d\n", sizeof(&p+1)); 4/8
printf("%d\n", sizeof(&p[0]+1)); 4/8
printf("%d\n", strlen(p)); 6
printf("%d\n", strlen(p+1)); 5
printf("%d\n", strlen(*p)); err
printf("%d\n", strlen(p[0])); err
printf("%d\n", strlen(&p)); 随机值
printf("%d\n", strlen(&p+1)); 随机值
printf("%d\n", strlen(&p[0]+1)); 5
例5、
int main()
{
inta[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
return 0;
}
sizeof 计算对象所占内存的大小,单位是字节。
printf("%d\n",sizeof(a)); 48
printf("%d\n",sizeof(a[0][0])); 4
printf("%d\n",sizeof(a[0])); 16 第一行的大小
printf("%d\n",sizeof(a[0]+1)); 4/8 第一行首元素的地址+1是第一行第二个元素的地址
printf("%d\n",sizeof(*(a[0]+1))); 4 第一行第二个元素
printf("%d\n",sizeof(a+1)); 4/8 a表示二维数组第一行的地址,a+1是第二行的地址
printf("%d\n",sizeof(*(a+1))); 16 对第二行的地址解引用
printf("%d\n",sizeof(&a[0]+1)); 4/8 第二行的地址
printf("%d\n",sizeof(*(&a[0]+1))); 16 第二行的大小printf("%d\n",sizeof(*a)); 16 第一行的大小
printf("%d\n",sizeof(a[3])); 16 第四行的大小,此时虽然越界,但没有访问,所以可以正常运行。
例6、
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int*ptr= (int*)(&a+1);
printf( "%d,%d", *(a+1), *(ptr-1));
return0;
}
结果是2、5
例7、
struct Test
{
int Num;
char*pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
p=0x100000;
printf("%p\n", p+0x1);
printf("%p\n", (unsignedlong)p+0x1);
printf("%p\n", (unsignedint*)p+0x1);
return0;
}
答案是:
00100014 当结构体指针+1时,加的是结构体的大小,所以加20,又因为是16进制表示
00100001 指针变量p被转换成无符号长整型变量,所以+1是就是数值直接+1
00100004 指针变量p被转换成整形指针,+1 就是加一个整形的大小
例8、
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);
return 0;
}
答案 0x4 0x20000000
例9、
#includeint main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
答案是:1;因为花括号中的小括号相当于逗号表达式,所以数组 a 的初始化相当于,a[3][2]={1,3,5};而 a[0]是第一行的地址,打印时,打印第一行的首元素。
例10、
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]);
return0;
}
答案: FFFFFFFC, -4
p[4][2] 等价于 *(*(p+4)+2) ; p 最初是数组名,也就是数组首元素的地址,p是一个数组指针,p+1相当于,向后跳过四个元素,而指针-指针得到的是指针之间的元素个数。自行画图
例11、
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));
return 0;
}
答案:10 5
例12、
int main()
{
char*a[] = {"work","at","alibaba"};
char**pa=a;
pa++;
printf("%s\n", *pa);
return 0;
}
答案:at
因为 char *a[] 中存的是这三个字符串的首字符的地址;
char** pa 中存的是 a 的地址;
pa 最初是指向 a 数组的第一个元素,即 "work" 中w的地址;
pa++ 后指向了 a 数组中第二个元素,即 "at" 中 a 的地址;
又因为数组中每个字符串最后都有一个 \n 所以最后打印 at。
例13、
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);
return0 ;
}
答案: POINT ER ST EW
*cpp[-2] 等价于 **(cpp-2)+3;
cpp[-1][-1] 等价于 *(*(cpp-1)-1)+1`;
C8 39
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章名称:【C语言进阶】二、指针-创新互联
文章链接:http://cdiso.cn/article/dicjoo.html