0

我有一个程序可以从命令行使用 argv 接受字符输入。我使用 strcpy 将输入 argv[1] 复制到已分配内存的名为 structptr 的指针(它从 struct 转到 structptr->words)。然后,我从指针 structptr 指向另一个指针的内存中逐个字符地复制该指针,该指针指向已分配的内存。在我复制了一个字符后,我打印该元素 [c] 以确保它已被正确复制(它具有)。然后我完成了所有字符的复制并将结果返回给一个字符指针,但由于某种原因它是空白/空。每次复制字符后,我都会检查前面的元素是否正确,但它们不再显示([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;
4

3 回答 3

2

一开始我以为是这个问题:

char *words=malloc(sizeof(char))正在分配 1 个字节(大小为 1 个字符)。您可能的意思是char *words = malloc(strlen(ptr->words)+1);-您可能想对 ptr 进行空检查,并且它是成员,只是为了安全起见。

然后我看到了realloc。您的 realloc 始终短 1 个字符。当 i = 0 时,您分配 1 个字节然后点击循环,递增i并将一个 char 1 放在重新分配数组的末尾(在索引 1 处)

此外,您的strcpyin main 还没有在持有人中分配任何内存。

于 2013-09-17T23:37:16.960 回答
0

在这两行中,

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

需要在大小上加一以容纳 nul 终止符。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';
于 2013-09-17T23:50:29.527 回答
0

仅供参考:您的描述涉及structptr但您的代码使用struct StructHolderand 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;
}

它应该是:

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();然而,它并非没有问题。

于 2013-09-18T00:03:31.567 回答