You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

函数分配的堆内存为何表现如栈内存?C指针传参问题排查

堆内存分配后指针失效问题排查

问题描述

我花了两天排查,查了不少帖子还是搞不懂堆内存的异常情况。我想写个程序,从命令行参数(char* argv[])获取密码,在堆上分配char* buffer存储输入,再和硬编码的char* password比对。

我在main()里声明了指针char* buffer,让AllocateBuffer()接收这个指针作为参数,用malloc给它分配内存。我没返回指针地址,觉得指针在main()里声明,分配的堆内存之后手动free就行。

在AllocateBuffer()里我把malloc分配的内存填成'A',验证下来一切正常,但调用StoreBuffer()尝试存储目标内容时,发现指针指向的内存块没了,就像栈内存一样!

char* buffer指针在main()里,分配的内存明明在堆上,这完全不符合预期。我是C语言新手,之前学的都说指针是传引用,到底哪里错了?我漏了什么?

附代码

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

int GetBufferLength(int args_num, char* argsv[])
{
    unsigned int blen = 0;
    for (int i = 1; i < args_num; i++)
    {
        blen += strlen(argsv[i]) + 1; 
    }
    printf("BufferLength is :%u\n", blen);
    return blen;
}

int AllocateBuffer(char* bufferName, int bufferLen)
{
    bufferName = malloc(sizeof(char) * bufferLen);
    if (bufferName != NULL)
    {
        printf("buffer Allocation Ok !!!\n");
        for (int i = 0; i < bufferLen; i++)
        {
            if (i == bufferLen - 1)
            {
                *(bufferName + i) = '\0';
                printf("End address that buffer points to in Heap : %p\n", (bufferName + i));
                printf("*(bufferName+%d) : %c\n", i, *(bufferName + i));
                break;
            }
            *(bufferName + i) = 'A';
            printf("*(bufferName+%d) : %c\n", i, *(bufferName + i));
        }
        return 1;
    }
    else
    {
        printf("Could not allocate buffer!!!\n");
        return 0;
    }
}

// 这里只是做缓冲区检查,实际代码已省略以便理解
void StoreBuffer(char* bufferName, int buffer_length, const char* argsv[], int argsc)
{
    printf("%s", bufferName);
}

// 以下函数仅展示程序流程,可跳过直接看main()
void CompareBuffer(char* bufferName, char* string)
{
    printf("CompareBuffer : %s", bufferName);
    if (strcmp(bufferName, string) == 0)
    {
        printf("Password correct.\n");
    }
    else
    {
        printf("Password NOT correct.\n");
    }
}

void DeallocBuffer(char* bufferName)
{
    free(bufferName);
    bufferName = NULL;
}

// main()
int main(int argc, char* argv[])
{
    char* password = "super secret";
    int bufferlength = GetBufferLength(argc, argv);

    char* buffer = NULL; 

    if (AllocateBuffer(buffer, bufferlength))
    {      
          // 这里是出错点:Storebuffer()中buffer为null,见下方命令行输出
          StoreBuffer(buffer, bufferlength, argv, argc);
        
         //CompareBuffer(buffer, password);
         //DeallocBuffer(buffer);
    }

    return 0;
}

命令行输入与运行结果

C:\Users\Strakizzz\Desktop\C\experiment\experiment\atrocity\bin>atrocity32.exe super secret
BufferLength is :13
buffer Allocation Ok !!!
*(bufferName+0) : A
*(bufferName+1) : A
*(bufferName+2) : A
*(bufferName+3) : A
*(bufferName+4) : A
*(bufferName+5) : A
*(bufferName+6) : A
*(bufferName+7) : A
*(bufferName+8) : A
*(bufferName+9) : A
*(bufferName+10) : A
*(bufferName+11) : A
End address that buffer points to in Heap : 00AF6C84
*(bufferName+12) :
(null)

问题根源与解决方案

问题根源

C语言里所有参数传递都是传值,包括指针。你传给AllocateBuffer()的buffer是原指针的副本,函数里给这个副本赋值malloc返回的堆地址,完全不会改变main()里原buffer的值——原buffer始终是NULL,所以调用StoreBuffer()时传的是NULL,自然输出(null)。

所谓“指针传引用”是误解,指针本身也是一个值(内存地址),传递指针本质是把这个地址值复制了一份传给函数,函数修改的是副本,和原指针无关。

修复方法

有两种常见的修复方式:

方法一:让AllocateBuffer()返回分配好的指针

修改函数的签名和实现,直接返回malloc的结果:

char* AllocateBuffer(int bufferLen)
{
    char* bufferName = malloc(sizeof(char) * bufferLen);
    if (bufferName != NULL)
    {
        printf("buffer Allocation Ok !!!\n");
        for (int i = 0; i < bufferLen; i++)
        {
            if (i == bufferLen - 1)
            {
                *(bufferName + i) = '\0';
                printf("End address that buffer points to in Heap : %p\n", (bufferName + i));
                printf("*(bufferName+%d) : %c\n", i, *(bufferName + i));
                break;
            }
            *(bufferName + i) = 'A';
            printf("*(bufferName+%d) : %c\n", i, *(bufferName + i));
        }
    }
    else
    {
        printf("Could not allocate buffer!!!\n");
    }
    return bufferName;
}

然后修改main()里的调用逻辑:

buffer = AllocateBuffer(bufferlength);
if (buffer != NULL)
{
    StoreBuffer(buffer, bufferlength, argv, argc);
    // CompareBuffer(buffer, password);
    // DeallocBuffer(buffer);
}

方法二:传递指针的指针(char**)

通过传递指针的地址,让函数能直接修改原指针的值:

int AllocateBuffer(char** bufferName, int bufferLen)
{
    *bufferName = malloc(sizeof(char) * bufferLen);
    if (*bufferName != NULL)
    {
        printf("buffer Allocation Ok !!!\n");
        for (int i = 0; i < bufferLen; i++)
        {
            if (i == bufferLen - 1)
            {
                *(*bufferName + i) = '\0';
                printf("End address that buffer points to in Heap : %p\n", (*bufferName + i));
                printf("*(*bufferName+%d) : %c\n", i, *(*bufferName + i));
                break;
            }
            *(*bufferName + i) = 'A';
            printf("*(*bufferName+%d) : %c\n", i, *(*bufferName + i));
        }
        return 1;
    }
    else
    {
        printf("Could not allocate buffer!!!\n");
        return 0;
    }
}

修改main()里的调用:

if (AllocateBuffer(&buffer, bufferlength))
{
    StoreBuffer(buffer, bufferlength, argv, argc);
    // CompareBuffer(buffer, password);
    // DeallocBuffer(buffer);
}

额外提示

你的DeallocBuffer()也存在同样的问题:函数里的bufferName是原指针的副本,把它设为NULL不会改变main()里的原指针。如果想在函数内把原指针置空,同样需要传递指针的指针;或者在main()里调用free(buffer)后,手动把buffer = NULL。

内容的提问来源于stack exchange,提问作者Sotiris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:15:53