无法将字符从指针复制到另一个指针(两者都分配了内存)

时间:2013-09-17 23:34:17

标签: c

我有一个程序,它使用命令行中的argv接受char输入。我使用strcpy将输入argv [1]复制到一个名为structptr的指针(它转到structptr->来自struct的单词),其中已经分配了内存。然后我从内存中逐字符复制指针structptr指向另一个指向已指定内存的字的指针。在我复制了一个字符后,我打印了该元素[c],以确保它已被正确复制(它有)。然后我完成复制所有字符并将结果返回到char指针但由于某种原因它是空/ null。每次复制字符后,我检查前面的元素是否正确,但它们不再显示([c-2],[c-1],[c])。这是我的代码:

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

struct StructHolder {
char *words;
};
typedef struct StructHolder Holder;

char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
 words[i]=ptr->words[i];
 words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}

int main(int argc, char **argv){

Holder *structptr=malloc(sizeof(Holder));
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
char *charptr;
charptr=(GetCharacters(structptr));
printf("%s\n", charptr);

return 0;

3 个答案:

答案 0 :(得分:2)

起初我认为这是问题所在:

char *words=malloc(sizeof(char))分配1个字节(sizeof 1个字符)。你可能意味着char *words = malloc(strlen(ptr->words)+1); - 你可能想要检查ptr和它的成员只是为了安全。

然后我看到了realloc。你的realloc总是1 char。当i = 0时,你分配1个字节然后点击循环,增加i并将char 1放在重新分配数组的末尾(在索引1处)

此外,你的strcpy在主要内容中没有为持有者分配任何内存。

答案 1 :(得分:0)

在这两行中,

structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);

需要添加一个大小来保存nul-terminator。 strlen(argv[1])应为strlen(argv[1])+1

我认为循环中也会发生同样的事情,并且它应该更大1.根据定义,sizeof(char)总是1,所以:

 ...
 words=realloc(words,i+2);
}
words=realloc(words,i+2); // one more time to make room for the '\0'
words[strlen(ptr->words)]='\0';

答案 2 :(得分:0)

仅供参考:您的说明涉及structptr,但您的代码使用struct StructHolderHolder

此代码是一场灾难:

char *GetCharacters(Holder *ptr){
    int i=0;
    char *words=malloc(sizeof(char));
    for(i;i<strlen(ptr->words);i++){
        words[i]=ptr->words[i];
        words=realloc(words,sizeof(char)+i);
    }
    words[strlen(ptr->words)]='\0';
    return words;
}

应该是:

char *GetCharacters(const Holder *ptr)
{
    char *words = malloc(strlen(ptr->words) + 1);
    if (words != 0)
        strcpy(words, ptr->words);
    return words;
}

甚至:

char *GetCharacters(const Holder *ptr)
{
    return strdup(ptr->words);
}

所有人都认为传递结构类型是有道理的;没有明显的理由说明为什么你不只是通过const char *words

解析'灾难'(并忽略参数类型):

char *GetCharacters(Holder *ptr){
    int i=0;

确定到目前为止,虽然您不打算更改结构,因此它可能是const Holder *ptr参数。

    char *words=malloc(sizeof(char));

分配一个字节非常昂贵 - 比调用strlen()更昂贵。这不是一个好的开始,虽然本身就没有错。但是,您不会检查内存分配是否成功。这是一个错误。

    for(i;i<strlen(ptr->words);i++){

i;第一个词很奇怪。您可以编写for (i = 0; ...(可能会在i的定义中省略初始值设定项,或者您可以编写for (int i = 0; ...

在这样的循环中反复使用strlen()也是坏消息。你应该使用:

    int len = strlen(ptr->words);
    for (i = 0; i < len; i++)

下一步:

        words[i]=ptr->words[i];

这项任务不是问题。

        words=realloc(words,sizeof(char)+i);

realloc()分配是个问题。如果返回空指针,则丢失了对先前分配的内存的唯一引用。因此,您需要单独保存返回值,对其进行测试,并且仅在成功时进行分配:

        void *space = realloc(words, i + 2);  // When i = 0, allocate 2 bytes.
        if (space == 0)
            break;
        words = space;

这会更好/更安全。它并不完全干净;将break;替换为{ free(words); return 0; }以提前退出可能会更好。但是,一次分配一个字节的整个业务并不是正确的方法。您应该计算出要分配的空间,然后一次性分配。

    }
    words[strlen(ptr->words)]='\0';

您可以使用i代替strlen(ptr->words)来避免重新计算长度。如果if (space == 0) break;被执行,这将带来正确的附带好处。

    return words;
}

此功能的其余部分没问题。

我没有花时间分析main();然而,它不是没有问题的。