Linux C高级第五天

指针函数

1. 概念

本质是函数,函数的返回值为指针。类比着指针数组。

指针数组:本质是数组,数组中存放指针。

数据类型 *数组名[元素个数];

int a[2][3];

int *arr[2] ={a[0],a[1]};

//*(*(arr+i)+j) *(arr[i]+j) arr[i][j]

2. 定义格式

格式:

数据类型 *函数名(参数列表)

{

函数体;

return 地址; //当失败时一般返回NULL

}

3. 函数内开辟空间

案例一:

#include <stdio.h>

char *fun()
{
    char buf[32] = "hello";
    return buf;
}

int main(int argc, char const *argv[])
{
    char *p = fun();
    printf("%s\n", p);
    return 0;
}

结果未知,因为返回局部变量地址,函数调用结束后没有权限使用栈区的空间了所以结果是不可控的。如果被其他进程占用,可能会报段错误或者打印奇怪的东西。

修改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *fun()
{
    char *p = (char *)malloc(32);
    if (NULL == p)
    {
        printf("malloc lost\n");
        return NULL;
    }
    // p="hello"; //让p又指向了常量区的hello而不指向堆区了
    strcpy(p, "hello");

    return p;
}

int main(int argc, char const *argv[])
{
    char *p = fun();  
    if (NULL == p)
    {
        printf("fun err\n"); //如果函数返回值为NULL可以打印一句错误提示
        return -1;   //如果错误让主函数结束,程序不再往后运行了
    }
    printf("%s\n", p);
    free(p);
    p = NULL;
    return 0;
}

案例二:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void fun(char *p)  //p=NULL
{
    p = (char *)malloc(32);
    if (NULL == p)
    {
        printf("malloc lost\n");
    }

    strcpy(p, "hello");
}

int main(int argc, char const *argv[])
{
    char *p = NULL;
    fun(p);
    printf("%s\n", p);  //函数调用结束后,主函数中的p还是指向了NULL,打印所以段错误
    free(p);
    p = NULL;

    return 0;
}

报端错误:因为主函数中p指向了NULL,函数内改变形参p不会影响到主函数中的变量p, 所以函数调用完后主函数中的p还是指向了NULL。

修改:传递二级指针

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun(char **p) //p = &q;
{
    *p = (char *)malloc(32); //*p = *&q = q
    if (NULL == *p)
    {
        printf("malloc lost\n");
    }

    strcpy(*p, "hello"); //*p = *&q = q
}

int main(int argc, char const *argv[])
{
    char *q = NULL;
    fun(&q);                    //函数调用结束后,q指向了堆区空间
    printf("%s\n", q);
    free(q);
    q = NULL;

    return 0;
}

案例三:数组传递

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun(int arr[5])  //arr类型为int *, 本质还是传递指针
{
    arr[0] = 100;
    printf("%ld\n", sizeof(arr));
}

int main(int argc, char const *argv[])
{
    int a[5] = {1, 2, 3, 4, 5};
    fun(a);
    printf("%d\n", a[0]);

    return 0;
}

传递数组的形式是为了让用户知道要传递的是一个数组,但本质还是传递数组的首地址,也就是传递指针。

函数指针

1. 概念

本质时指针,指向了函数。类比着数组指针。

数组指针:本质是指针,指向了数组的指针。

数组指针定义格式:数据类型 (*指针名)[列数];

int a[2][3];

int (*p)[3] = a;

//p[i][j] *(p[i]+j) *(*(p+i)+j)

2. 定义格式

2.1

数据类型 (*指针名)(参数列表);

函数名:函数地址

2.2 基本用法

#include <stdio.h>

int add(int a, int b) //add: 函数名,也就是函数的地址
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int main(int argc, char const *argv[])
{
    int (*p)(int, int); //定义函数指针, 类型int (*)(int,int)
    p = add;

    printf("%d\n", p(1, 2));
    printf("%d\n", add(1, 2));

    p = sub;
    printf("%d\n", p(1, 2));
    printf("%d\n", sub(1, 2));

    return 0;
}

把函数指针当成参数传递给函数:

一种接口,多种方法:

#include <stdio.h>

int add(int a, int b) //add: 函数名,也就是函数的地址
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int test(int (*p)(int, int), int a, int b)  //p=add, a=5, b=6
{
    return p(a, b);  //add(5,6);
}

int main(int argc, char const *argv[])
{
    printf("%d\n", test(add, 5, 6));  //11
     printf("%d\n", test(sub, 5, 6)); //-1
    return 0;
}

结构体内成员是函数指针(不常用但是看内核原码可能会见到)

#include <stdio.h>

struct test
{
    int (*p)(int,int);
};

int add(int a,int b)
{
    return a+b;
} 

int main(int argc, char const *argv[])
{
    struct test x;
    x.p = add;
    printf("%d\n", x.p(1,2));

    return 0;
}

3. 函数指针数组

3.1 概念

本质是数组,数组中元素是函数指针

3.2 定义格式

数据类型 (*数组名[元素个数])(形参列表);

数据类型:和指向的函数返回值类型一致

形参列表:和指向的函数参数一致

3.3 赋值

int (*arr[3])(int,int) = {函数名};

#include <stdio.h>

int add(int a, int b) //add: 函数名,也就是函数的地址
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int main(int argc, char const *argv[])
{
    int (*arr[2])(int, int) = {add, sub};   //函数指针数组
    printf("%d %d\n", arr[0](1, 2), arr[1](3, 4));  

    return 0;
}

练习:

a) 一个整型数

int a;

b) 一个指向整型的指针

int *p=&a;

c)一个指向指针的指针,它指向的指针是一个指向一个整型数

int **q=&p;

d)一个有10个整型数的数组

int arr[10];

e)一个有10个指针的数组,该指针是指向一个整型数的

int *a[10];

f)一个指向有10个整型数数组的指针

int a[1][10]

int (*p)[10]=a;

int b[10]; //b=&b[0] &b表示整个数组的地址了也就是行地址

p = &b;

g)一个指向函数的指针, 该函数有一个整型参数并返回一个整型数

int (*p)(int);

h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

int (*a[10])(int);

条件编译

按照条件是否满足决定代码是否被编译,是预处理指令。

简单来说就是 后面的条件语句(condition)如果执行结果不为0,则该#if语句块内的代码会被编译,否则就不会被编译。

1. 根据宏是否定义

#define 宏名

#ifdef 宏名

/*code1*/

#else

/*code2*/

#endif

执行顺序:宏名如果定义则编译code1,否则编译code2

例子:

2. 根据宏值

#define 宏名 值

#if 宏名

/*code1*/

#else

/*code2*/

#endif

执行顺序:宏的值为非0则编译code1,为0则编译code2

例子:

#include <stdio.h>

#define DEF 0

int main(int argc, char const *argv[])
{
#if DEF  //如果DEF为真则编译下面代码,否则编译#else下面代码
    printf("hello\n");
#else
    printf("world\n");
#endif
    return 0;
}

3. 防止头文件重复包含

放在头文件中:

#ifndef 宏名

#define 宏名

/*code*/

#endif

报错原因:多次引用了包含struct test结构体定义的头文件,所以造成结构体重复定义

 C高级到今天算是告一段落,从周四开始给大家更新数据结构笔记。大家可以运用目前所学知识进一步完善学生成绩管理系统了。

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值