我有一个程序,它使用命令行中的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;
答案 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 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;
}
应该是:
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()
;然而,它不是没有问题的。