将缓冲区传递给函数进行写入

Passing buffer to function for writing

提问人:mv_p 提问时间:8/13/2022 更新时间:8/14/2022 访问量:803

问:

我正在尝试实现一个快速原型程序来准备一条我打算用作 tcp 套接字通信协议的消息。 我是这方面的新手,我不太明白为什么要运行以下打印(null)。我是否未能将指针传递到子例程?

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

const char *header = "testhd";

void pack_message(char *body, char *buffer)
{
    size_t body_size, msg_size, buffer_size;
    char hex_size[11];
    
    body_size = strlen(body);
    snprintf(hex_size, 11, "0x%x", body_size);
    msg_size = 16 + body_size;
    buffer_size = msg_size + 1;
    
    if (!buffer){
        buffer = malloc(buffer_size);
    }else{
        buffer = realloc(buffer, buffer_size);
    }
    
    memset(buffer, 0, buffer_size);
    
    strcat(buffer, header);
    strcat(buffer, hex_size);
    strcat(buffer, body);
}

int main(){
    char *buffer = NULL;
    char *body = "testmsg";
    pack_message(body, buffer);
    printf("%s", buffer);
    return 0;
}
C 指针 内存管理 动态 malloc

评论

0赞 Some programmer dude 8/13/2022
请记住,C 语言中的参数是按值传递的。这意味着调用中的值将复制到函数局部参数变量中。对局部参数变量的任何更改(如赋值)只会发生在该局部变量上。调用中使用的原始值不受影响。请在 C 中通过引用研究模拟传递。提示:它涉及指针和指向指针的运算符。&
0赞 Fe2O3 8/13/2022
当你弄清楚了缓冲区问题时,你仍然需要处理释放分配块的问题(否则程序会泄漏内存......
1赞 Fe2O3 8/13/2022
你能不能在调用者中声明(或分配)一个足够大的缓冲区,然后让你的“pack”函数尽可能多地填充(不要溢出!

答:

0赞 WojciechS 8/13/2022 #1

请注意,函数和函数是指向同一地址的两个不同指针。 因此,在您的案例中,functiom 使用本地指针,这就是运行您的代码打印的原因。char *buffermainchar *bufferpack_messageNULLpack_messagenull

为了让你的代码工作,你可以采取一种方法,你把指针本身的地址作为参数传递给函数,这样函数可以看起来像这样:pack_messagemain

int main(){
    char *buffer = NULL;
    char *body = "testmsg";
    pack_message(body, &buffer);
    printf("%s", buffer);
    return 0;
}

您的函数应更改为:pack_message

void pack_message(char *body, char **buffer)
{
    size_t body_size, msg_size, buffer_size;
    char hex_size[11];
    
    body_size = strlen(body);
    snprintf(hex_size, 11, "0x%zx", body_size);
    msg_size = 16 + body_size;
    buffer_size = msg_size + 1;
    
    if (NULL == *buffer){
        *buffer = malloc(buffer_size);
    }else{
        *buffer = realloc(*buffer, buffer_size);
    }
    
    memset(*buffer, 0, buffer_size);
    
    strcat(*buffer, header);
    strcat(*buffer, hex_size);
    strcat(*buffer, body);
}

请注意,我还更改了一个潜在的问题:

snprintf(hex_size, 11, "0x%zx", body_size);

由于是类型,因此使用是更好的主意,因为可以与 不同大小,有关 printf 的详细信息,请查看: https://cplusplus.com/reference/cstdio/printf/body_sizesize_t%zxsize_tunsigned integer

可以采用类似的方法,特别是当它的值将更长的字符串时。 为了进一步改进,我建议重新设计函数以返回指向已分配缓冲区的指针,因为它将降低在不再需要时忘记释放内存的机会。char *body = "testmsg";pack_message

评论

0赞 mv_p 8/13/2022
我之前尝试过这个(模拟通过引用传递),但我从 realloc 收到一个错误,没有意识到旧参数和新参数都需要取消引用。现在它正在工作,谢谢!只是为了澄清。检查包中的空指针(if 块),是否也应该是“if (!*pointer)”表示取消引用?
0赞 WojciechS 8/14/2022
你是对的。我错过了这一点,实际上不建议将其与布尔上下文中的处理方式相同。nullfalse
0赞 mv_p 8/14/2022
哦,好吧,我看到了一种非常普遍的做法,即直接测试空指针而不是 ==Null,但我想这假设 null=0 这与实现相关?
0赞 WojciechS 8/15/2022
我会说它更多的是关于可读性,因为当您看到与“NULL”的比较时,您可以更快地理解这是关于指针而不是常规变量。正如你提到的,还有一种非常非常罕见的情况,即“NULL”可能与零不同。在实践中,null 指针指向不存在的地址,因此当作为函数指针调用时,您具有未定义的行为。您可能希望在软件级别捕获此类事件,而不依赖于执行故障处理程序的硬件。