C语言 —— 指针(4)

动态内存分配

动态内存需要手动申请,手动归还,其内存是开辟在堆区。

申请的函数为:

void *malloc(size_t size) (需包含头文件#include<stdlib.h>)

size:要分配的内存大小,以字节为单位。申请的空间是连续的,成功时返回指向内存分配的指针(类型为void * 型,通常需要进行强制类型转换),失败时返回空指针(NULL)。需手动管理内存,所分配的内存不会自动释放,必须调用free()避免内存泄漏。返回的指针会适当对齐,适合任何数据类型。如:分配一个整型数组

cs 复制代码
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    int n = 5;
    int *a = (int *)malloc(n * sizeof(int));
    if(a == NULL)
    {
        printf("分配内存失败\n");
        return 1;
    }
    int i = 0;
    for(i = 0; i < n; ++i)
    {
        a[i] = i + 1;    
    }
    for(i = 0; i < n; ++i)
    {
        printf("%d\n",a[i])
    }
    free(a);
    a = NULL;
    return 0;
}

释放内存后未将指针置为NULL称为悬空指针,可能导致非法访问。

动态内存重新分配

形式:void *relloc(void *p,size_t newsize);

参数p:指向之前分配的内存的指针

参数size:所需要新的内存大小

返回值指向新的内存,与原来的p指向的内存可能不同。

特点:数据保留,拷贝原来的内容到新的空间。

eg:如原来申请内存只能容纳长度为10的一维整型数组,现在改为可容纳长度为20的一维整形数组。

cs 复制代码
void printArray(int *a,int len)
{
    int i;
    for(i < 0 ;i < len;++i)
    {
        printf("%2d ",*(a + i));
    }
    puts("");
}


int main(void)
{
    int n = 10;
    int *p = malloc(n * sizeof(int));
    int i;
    for( i = 0;i < n;++i)
    {
        *(p + i) = i + 1;
    }
    int m = 20;
    int *q = realloc(p, m * sizeof(int));
    p = q;
    for(i = 10;i < m; ++i)
    {
        *(p + i) = i + 1;
    }
    free(p);
    p = q = NULL;
    printArray(p,m);
    return 0;
}

函数指针

它存储的是函数的地址,而不是数据变量的地址。通过函数指针,可以动态的调用不同的函数,实现回调。

基本语法:

定义函数

cpp 复制代码
int add(int a,int b)
{
    return a + b
}

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

1、定义函数指针: 返回值类型(*指针变量名)(参数列表)

如回调上述代码:int (*pfn)(int , int);

2、初始化指针

cpp 复制代码
pfn = &add;
或
pfn = add;

(函数名本身代表函数的入口地址)

即:

cs 复制代码
int add(int a,int b)
{
    return a + b
}

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

int(*pfn)(int,int) = add;

指针便指向了add函数(改为sub,便指向sub)

3、通过函数指针调用函数

cs 复制代码
int div3(int n)
{
   return n % 3 == 0;
}

int div5(int n)
{
   return n % 5 == 0;
}

int fn(int n)
{
    return 1;
}

void printArray(int *a,int len,int(*pfn)(int))
{
    int i;
    for(i = 0;i < len; ++i)
    {
        if(pfn(*(a + i)))
        {
            printf("%2d ",*(a + i));
        }
    }
    puts("");
    
}

主函数调用printArray传参,最后一个传入回调函数的函数名。

指针数组

指针数组是指一个数组,其元素都是指针,简单地说,数组中的每一个元素存储都是一个内存地址,而不是直接存储数据。

当它作为函数参数,形参是指向指针的指针。

cs 复制代码
void printStrings(char **p,int len)
{
    int i;
    for(i = 0;i < len;++i)
    {
        puts(p[i]);
    }
}

void reverseStrings(char **p,int len)
{
    int i;
    for(i = 0;i < len / 2;++i)
    {
        char *t;
        t = p[i];
        p[i] = p[len - i - 1];
        p[len - i - 1] = t;
    }
}

char *maxStrings(char **p,int len)
{
    char *max = p[0];
    int i;
    for(i = 1;i < len; ++i)
    {
        if(strcmp(max,p[i]) < 0)
        {
            max = p[i];
        }
    }
    return max;
}

void sortStrings(char **p,int len)
{
    int i,j;
    for(i = 0; i < len - 1;++i)
    {
        for(j = i + 1;j < len; ++j)
        {
            if(strcmp(p[i] , p[j]) > 0)
            {
                char *t;
                t = p[i];
                p[i] = p[j];
                p[j] = t;
            }
        }
    }
}

int main(void)
{
    char *s[3] = {"Hello","World!","China"};
    int len = sizeof(s) / sizeof(*s);
    //reverseStrings(s,len);
    //printStrings(s,len);
    //printf("%s\n",maxStrings(s,len));
    sortStrings(s,len);
    printStrings(s,len);
    return 0;
}
相关推荐
屁股割了还要学34 分钟前
【数据结构入门】时间、空间复杂度的计算
c语言·开发语言·数据结构·c++·算法
倒悬于世41 分钟前
ThreadLocal详解
java·开发语言·jvm
啃火龙果的兔子2 小时前
快速搭建Java服务指南
java·开发语言
未来之窗软件服务2 小时前
智慧收银系统开发进销存库存统计,便利店、水果店、建材与家居行业的库存汇总管理—仙盟创梦IDE
java·开发语言·ide·进销存·仙盟创梦ide·东方仙盟·收银台
pusue_the_sun2 小时前
从零开始搞定类和对象(上)
开发语言·c++
归云鹤2 小时前
QT信号和槽怎么传输自己定义的数据结构
开发语言·数据结构·qt
ytttr8732 小时前
MATLAB 实现 SRCNN 图像超分辨率重建
开发语言·matlab·超分辨率重建
饭碗的彼岸one3 小时前
重生之我在10天内卷赢C++ - DAY 1
linux·开发语言·c++·经验分享·笔记·学习方法
DIY机器人工房3 小时前
【科普】在STM32中有哪些定时器?
c语言·嵌入式·定时器·diy机器人工房
项目申报小狂人3 小时前
2025年1中科院1区顶刊SCI-投影迭代优化算法Projection Iterative Methods-附完整Matlab免费代码
开发语言·算法·matlab