如何解决当我打印修改后的字符串时从函数返回后,它显示了垃圾值
int main()
{
//CODE
printf("Enter the destination string : ");
char *dest_string = (char *)malloc(sizeof(char));
int le = 0;
while(dest_string[le - 1] != '\n')
{
dest_string = (char *)realloc(dest_string,sizeof(char) * (le + 1) );
dest_string[le] = getchar();
le++;
}
*(dest_string + le - 1) = '\0';
le = 0;
printf("Enter the source string : ");
char *source_string = (char *)malloc(sizeof(char));
le = 0;
while(source_string[le - 1] != '\n')
{
source_string = (char *)realloc(source_string,sizeof(char) * ( le + 1 ) );
source_string[le] = getchar();
le++;
}
*(source_string + le - 1) = '\0';
_concatenate(dest_string,source_string);
puts(dest_string);
free(dest_string);
free(source_string);
exit(0);
}
/* following function takes two parameter,first parameter is
destination string and second parameter is source string
This function makes changes to destination string by
appending the source string to it */
void _concatenate(char *dest_string,char *source_string){
int le = 0; // loop enumerator
int dest_string_len = strlen(dest_string);
while(source_string[le] != '\0')
{
dest_string = (char *)realloc(dest_string,sizeof(char) * (dest_string_len + le + 1) );
*(dest_string + dest_string_len + le) = *(source_string + le);
le++;
}
dest_string = (char *)realloc(dest_string,sizeof(char) * (dest_string_len + le) );
*(dest_string + dest_string_len + le ) = '\0';
puts(dest_string);
return ;
}
解决方法
这里有许多需要注意的问题,主要和次要的,没有特定的顺序:
-
main
的两个标准签名是:int main(int argc,char **argv)
和int main(void)
。 -
应避免使用以
_
开头的标识符,除了极少数例外,reserved for the implementation。 -
exit(0)
在很大程度上是不必要的,因为main
将隐式return 0;
如果它达到其终止}
(自 C99 ). -
sizeof (char)
是 guaranteed to be1
。 -
您不需要强制转换
malloc
的返回值,因为void *
可以安全且隐式地转换为任何其他指针类型。投射返回值是 considered a bad practice。 -
正如评论中指出的,
if (dest_string[le - 1] != '\n')
将在第一次迭代时访问dest_string[-1]
,这是越界的。这是undefined behavior。当然,这也适用于涉及source_string
的循环。 -
您需要检查
*alloc
函数是否失败,通过测试它们的返回值是否为NULL
。不能盲目的重新赋值realloc
的返回,因为在失败的情况下,原来的指针仍然有效,迟早要free
原来的指针。 -
另一方面,如果
realloc
成功,则应认为先前的指针值无效。虽然内存块的基地址可能没有改变是真的,但如果不先检查,你就无法知道这一点,而且测试它们是否相同是毫无意义的。如果返回值不是NULL
,只需使用该指针。 -
你需要测试
getchar
是否返回文件结束标记(EOF
),否则,如果它发生了,你将循环直到用完记忆。
main
末尾的 您没有向我们展示任何 headers,所以我必须假设您没有包含它们。你需要
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
每当您重复自己时,几乎总是表明您应该将这些部分重新组合成某种抽象形式。在此示例中,您为从 stdin
构建字符串而编写的相同代码部分应简化为一个函数。
由于您没有错误检查 realloc
,我们必须假设它总是成功。因此,我们列表中的 #8 向我们展示了 dest_string
中的 main
在调用 _concatenate
后不能可靠地假定指向有效内存,可能具有 移动位于该指针处的数据,并释放旧数据
如果没有足够的空间来扩大 ptr 指向的内存分配,realloc() 会创建一个新分配,复制 ptr 指向的旧数据以适合新分配,释放旧分配,并返回指向已分配内存的指针。
因此 puts(dest_string)
可能会访问无效或未初始化的内存,而 free(dest_string)
可能会导致 double free。
您使用 strlen
获取目标字符串的长度,但随后您手动计算并复制源字符串。使用其他标准库函数使这更简洁:
char *concat(char *dest,char *src) {
size_t dest_len = strlen(dest),src_len = strlen(src);
char *p = realloc(dest,dest_len + src_len + 1);
return p ? strcat(p,src) : NULL;
}
如您所见,管理内存和执行实际的字符串操作应该是分开的; strcat
不关心目标缓冲区是否是动态分配的,只要调用者确保有足够的空间来存储结果即可。
为每个字节重新分配不是一个很好的策略,但它很简单,而且确实有效。
这是一个完整的示例程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concat(char *,char *);
char *input(const char *);
int main(void) {
char *dest = input("Enter the destination string : "),*source = input("Enter the source string : "),*result;
if (!dest || !source || !(result = concat(dest,source))) {
free(dest);
free(source);
fprintf(stderr,"Failed to allocate memory.\n");
return EXIT_FAILURE;
}
puts(result);
free(result);
free(source);
}
char *concat(char *dest,src) : NULL;
}
char *input(const char *msg) {
int ch;
size_t length = 0;
char *buf = malloc(1),*rebuf;
if (!buf) return NULL;
if (msg) printf("%s",msg);
while ((ch = getchar()) != EOF && ch != '\n') {
if (!(rebuf = realloc(buf,length + 1))) {
free(buf);
return NULL;
}
(buf = rebuf)[length++] = ch;
}
buf[length] = '\0';
return buf;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。