Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
结构中的char*,指向char数组,然后使用strncpy。试图避免动态分配内存_C_Pointers_Struct_Buffer_Dynamic Allocation - Fatal编程技术网

结构中的char*,指向char数组,然后使用strncpy。试图避免动态分配内存

结构中的char*,指向char数组,然后使用strncpy。试图避免动态分配内存,c,pointers,struct,buffer,dynamic-allocation,C,Pointers,Struct,Buffer,Dynamic Allocation,此代码在strncpy调用时失败。我不能使用动态分配的内存。处理这个问题的最佳方法是什么?为什么当name*指向nameBuf[20]一个char数组,然后使用strncpy时,这就不起作用了 谢谢首先,年龄只有3岁,您正在尝试写入4个字节、3个数字和一个空值。另外,通常strncpy的length参数是目标的大小减去1,这样您就有空间添加null。如果源字符串较短,strncpy将添加null struct person { char age [3]; char * name;

此代码在strncpy调用时失败。我不能使用动态分配的内存。处理这个问题的最佳方法是什么?为什么当name*指向nameBuf[20]一个char数组,然后使用strncpy时,这就不起作用了


谢谢

首先,年龄只有3岁,您正在尝试写入4个字节、3个数字和一个空值。另外,通常strncpy的length参数是目标的大小减去1,这样您就有空间添加null。如果源字符串较短,strncpy将添加null

struct person
{
    char age [3];
    char * name;
};

char nameBuf[20];

person Natasha;
person * p_person;
p_person = &Natasha;

Natasha.name = nameBuf;

createPerson (person * resultingPerson, int p_age, const char * p_name)
{

    sprintf(resultingPerson->age, "%03d", p_age);

    strncpy(resultingPerson->name, p_name, strlen(p_name));
}


createPerson (p_person, 29, "Chelsea");
不过还是不干净。你能保证年龄是合理的,并且只传递19个或更少字符的短名称吗


注意:将sprintf更改为snprintf,因为下面的注释是正确的,sprintf是非常不安全的,正如您的代码示例所示

@chqrlie-您帮助我找到了我的问题。我的问题是我不想要字符串,只想要一个字符数组。当我使用sprintf时,它通过编写最后一个空字符(我没有预料到)来破坏我最初指向nameBuf[]的char*名称。我将其通过调试器,并观察缓冲区地址的变化。直到我读到你的评论,我才知道为什么会这样

我最终编写了自己的itoa,没有空字符,然后使用memcpy结束


谢谢你的帮助

为什么不分配内存呢?更好的是,为什么不C++?您可以通过自动清理获得对许多动态类型操作的内置支持;对于需要4个字符的格式%03d来说太小。strncpyresultingPerson->name,p_name,strlenp_name;不确保resultingPerson->name将有一个终止的空字符“\0”。永远不要使用strncpy。它并没有达到您期望的效果,99%的C程序员都不知道它的实际语义,几乎对所有实际的用例都没有用处。如果你认为我在这方面很武断,那就看看man strncpy吧。当然,你也不应该使用sprintf,因为正如你的例子所示,你有缓冲区溢出的风险。使用snprintf。另外,如果必须使用sprintf使用snprintf,那么您的代码是非常不安全的,memset是绝对不必要的,请使用strcpy并自己检查字符串的长度,这样strlen-memcpy组合会更好。@chqrlie-strncpy如果根据手册页使用,则可以安全使用。目标不是重写ops代码,而是回答ops问题,即出了什么问题。我同意,永远不要使用sprintf,但在回答问题时使用它可以说明问题代码失败的原因。@iharob-你是对的,memset完全不需要,可以依赖已经清除的缓冲区,或者因为我使用许多不同的机器和编译器,我通常只在最后一个字节写一个保护性的null
#define NAMEBUFSIZ 20
char namebuf[NAMEBUFSIZ];
typedef struct person
{
    char age [3];
    char *name;
} person;

person Natasha;
person * p_person;
p_person = &Natasha;
p_person->name = namebuf;

createPerson (person * resultingPerson, int p_age, const char * p_name)
{
    char tmpbuf[5];

    snprintf(tmpbuf, sizeof(tmpbuf), "%03d", p_age);
    memcpy(resultingPerson->age, tmpbuf, sizeof(resultingPerson->age));
    resultingPerson->name[NAMEBUFSIZ-1] = '\0';
    strncpy(resultingPerson->name, p_name, NAMEBUFSIZ-1);
}
createPerson (p_person, 29, "Chelsea");