C 指针数组函数之间的关联
可能经常会听到:指针常量、常量指针、指针数组、数组指针、指针函数、函数指针;函数指针数组,等这些听起来感觉向绕口令似的词汇;
可见数组、指针、函数之间是有很多联系的。比如看下面一段代码:
#include<stdio.h>
#include <string.h>
int main() {
char* str = "abc";
char* str1 = "12";
strcpy(str, str1);
return 0;
}
运行起来怎么还报错了呢?如果你回答不上来,那说明弄清上面这些名词后面的细节是十分有必要的!今天本文就带领读者回顾一下这些名词背后的知识点!
指针常量、常量指针
指针常量和常量指针,都是指针;
指针常量:
形如:const char * str,意思是告诉使用者,指针指向了常量,请你不要试图通过指针修改所指向的变量;这种常用在函数参数中,防止在函数内部不小心修改了指针指向的变量的值。
常量指针:
形如:char * const str,意思是告诉使用者,指针被声明为常量,不要试图修改这个指针的值;即:不要试图修改指针指向的地址;数组名貌似就有这种性质,声明数组后,不可使用数组名对数组再次赋值。
如何区分指针常量和常量指针
看const和*的位置,const在*的左边--常量指针;const在*的右边--指针常量。
指针数组、数组指针
#include <stdio.h>
#include <string.h>
int main(void) {
int arr[] = {1, 2, 3};
int (*p_arr)[] = &arr;//数组指针
printf("%d\n", (*p_arr)[1]);
char *s1[] = {"hello", "world", "!"};//指针数组
printf("%s\n", s1[2]);
return 0;
}

指针数组
看后面两个字,重在“数组”;指针数组,是说有一个数组,它是由指针类型元素组成。
数组指针
看后面两个字,重在“指针”;数组指针,是说有一个指针,它指向了一个数组。
指针函数、函数指针
指针函数
看后面两个字,重在“函数”;指针函数,是说有一个函数返回值类型是指针类型。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *mock(int size) {
return malloc(sizeof(int) * size);
}
int main(void) {
int *p = mock(5);
p[0] = 1;
p[1] = 3;
p[2] = 5;
p[3] = 7;
p[3] = 7;
free(p);
int number = p[2];
return 0;
}
看一下执行情况:

函数指针
看后面两个字,重在“指针”;函数指针,是说有一个指针变量,它指向一个函数。
#include <stdio.h>
#include <string.h>
int add(int a, int b) {
return a + b;
}
int main(void) {
int (*p_add)(int, int);//函数指针
p_add = &add;//将函数add的地址赋值给函数指针
int ret = (*p_add)(1, 2);
return 0;
}
看add函数在内存中是什么类型:

实用技巧
常量指针做函数形参
为防止在函数内部,通过指针修改函数外部变量的值;函数参数通常定义为常量指针。

现在可以回答本文最开始的示例代码中的不合理之处了吧?对,指针应声明为常量指针,告诉使用者,不要试图使用指针修改字符串的值。这种防御性编程是一种好习惯!
当然如果你确实要修改字符串,你可以将字符串字面量,交给字符数组。。。或者使用动态内存分配的方式。
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
int main(void) {
char arr[] = "hello"; //方式1
arr[1] = 'a';
const char *str = "hello";
char *new_str = (char *) malloc(strlen(str) + 1); //方式2
if (new_str != NULL) {
strcpy(new_str, str);
new_str[1] = 'a';
free(new_str);
}
return 0;
}
数组做函数形参
请看下面的函数形式:
#include <stdio.h>
void test1(int a[10]) {
printf("in test1 size is :%lu\n", sizeof(a));
}
void test2(int a[]) {
printf("in test2 size is :%lu\n", sizeof(a));
}
void test3(int *a) {
printf("in test3 size is :%lu\n", sizeof(a));
}
int main(void) {
int arr[10] = {0};
test1(arr);
test1(arr);
test1(arr);
return 0;
}
输出
in test1 size is :8
in test1 size is :8
in test1 size is :8
由于数组做函数形参会退化成指针,而对指针求sizeof得到的是指针类型占用的空间;并不能得到数组占用的空间;所以数组做函数形参时,通常还需再定义一个参数:数组的长度。
void test4(int arr[], int n);
函数指针做函数形参
使用函数指针做函数形参,可以实现函数回调的效果;如下面示例,便演示了一个简单的发布、订阅机制。
#include <stdio.h>
#include <strings.h>
typedef void (*func)(void);
int _index;
func func_arr[10];
void add_handler(void (*callback)()) {
if (callback != NULL && _index < 10) {
func_arr[_index++] = callback;
}
}
void raise_event() {
int n = 0;
for (; n < _index; n++) {
if (func_arr[n] != NULL) {
func_arr[n]();
}
}
}
void test1() {
printf("test1...\n");
}
void test2() {
printf("test2...\n");
}
int main(void) {
add_handler(test1);
add_handler(test2);
raise_event();
return 0;
}
效果:
test1...
test2...
以上便是数组、指针和函数之间的关联的介绍。

浙公网安备 33010602011771号