欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

程序员文章站 2024-01-01 17:28:58
...

0.指针和数组的定义与声明(说明指针和数组是不一样的)

//text.c
char arr[] = "abcdef"; //在text.c文件中定义数组
//main.c
ertern char *arr; // 调用其他源文件中的参数时要用ertern
int main()
{
    printf("%s\n", arr);
    return 0;
}
执行后程序崩溃;text.c中的arr[]占用了7个字节,main.c中的arr是个指针,所以只占了四
个字节,而指针中存放的是地址,所以就会误把字符''abcd''当做一个地址,去找这个地址所代
表的空间,然后输出这块空间上的字符串,但由于字符''abcd''所对应的ASCII转换成的地址无
法去访问,所以最后程序访问出错,直接崩掉

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

若想让输出的结果为正确的,则需要把paintf中的arr改为(char *)&arr,取出arr中的地址,
但因为arr原本就是char *类型的,再加上个&,就变成了char **类型,所以需要强制转换为
char *类型,也就是拿到了a的地址,然后在打印,结果就会是abcdef

//text.c
char *p = "abcdef";//在text.c文件中定义指针
//main.c
ertern p[];
int main()
{
    printf("%s\n", p);
    return 0;
}
执行结果为随机值;text.c中的p存放的是字符串"abcdef"'a'的地址,占4个字节,
main.c中的p[](未指定大小,所以最多为4个字节)则误把text.c中的这个地址当做字符串,
把没地址分成四份存起来,在printf中的p是首元素地址,也就是前1/4元素的值被转换成字符
形式输出来

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

若想输出为正确的值,则需要把printf中的p改成(char *)*(int *)p,因为p中存放的是a的
地址的首地址,先把p强制转化为int *形式(取出p中的4个字节)再解引用,得到八位十六进制
数,即为a的地址,因为要打印出字符串,所以要再强制转化为char *类型
或
把p改成*(char **)p,先把p当做是char *类型的,然后对char *类型的p取地址,就是
char **类型,再解引用,因为char **类型解引用取出的是四个字符,正好取到p中a的地址,
所以打印时刚好打出字符串"abcdef"

声明与定义指向的是同一块空间,但因为在链接是只查找参数名,所以链接时不会出现问题

1.指针数组

指针数组强调的是数组,所以它是一个数组,用来存放指针
例如:

int* arr[10] 存放整形指针的数组,数组包含10个元素;

char* arr[10] 存放字符形指针的数组,数组包含10个元素;

char** arr[10] 存放字符型二级指针的数组,数组包含10个元素。

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

2.数组指针

与上面相反,数组指针强调指针,所以他是个指针,指向一个数组
例如:

int arr[10] = {0};
int (*p) [10] = &arr;(因为[]的优先级比*高,所以要给*p加上(), 
否则这个表达式就是前面提到的指针数组)

void text(int (*p) [5])
{
    ...
}
int main()
{
    int arr[3][5] = {123456789101112131415};
    text(arr);
    return 0;
}

因为在main函数中传过去的arr是首元素地址,在二维数组中,首元素地址是第一行的地址,第一行则可以看成一个一维数组,数组中包含5个元素,这个数组的地址就是 int (*p) [5]
C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

3.函数指针

指向函数的指针变量
例:

void text()
{
    printf("hello world\n");
}

int main()
{
    void (*p)() = text;//这里的text与&text作用相同,都表示函数的地址
    (*p)();
    p();
    return 0;
}

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

从结果可以看出,(*p)()与p()的调用结果是相同的,因为C语言设计者为了方便初学者的理解
,所以可以写成(*p)()的形式,但要注意如果有*,就一定要(),否则就会出现错误,因这样写
最后会把函数的返回值解引用

4.函数指针数组

是一个数组,里面存放许多指向函数的指针

例如:

int (*p[10])(int);
[]的优先级高于*,所以p先和[]结合,说明这是一个数组,去掉名称看类型,这是一个函数指针
,所以是函数指针数组;包含函数返回值类型为int,函数参数类型也为int10个函数指针

转移表:
#include <stdio.h>

void 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;
}

int main()
{
    int x = 0;
    int y = 0;
    int ret = 0;
    int input = 0;
    int(*p[5])(int, int) = { 0, Add, Sub, Mul, Div };

    do
    {
        menu();

        printf("please choose:");
        scanf("%d", &input);

        if ((input >= 1) && (input <= 4))
        {
            printf("please input two numbers:");
            scanf("%d %d", &x, &y);
            printf("%d\n", ret = p[input](x, y));
        }

    } while (input);

    return 0;
}

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解
C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

当参数类型与返回类型相同时才可以使用函数指针数组,函数指针数组可以减少代码的数量,
以上代码若不用函数指针数组,用最基本的switch case语句,需要逐条列出来,代码长度
会大幅增加 

5.指向函数指针数组的指针

是一个指向数组的指针,数组中的元素都是函数指针

例如(借用函数指针数组的例子):

void (*a)(int, int) = Add;//指向函数Add的指针a;

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

void (*count[4])(int, int) = { Add, Sub, Mul, Div };
//count为函数指针数组,里面包含的元素为函数指针a,s,m,d;

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

void (*(*p)[4])(int, int) = &count;//p为指向函数指针数组count的指针;

C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解

上一篇:

下一篇: