当我打印修改后的字符串时从函数返回后,它显示了垃圾值

问题描述

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 ;
}

解决方法

这里有许多需要注意的问题,主要和次要的,没有特定的顺序:

  1. main 的两个标准签名是:int main(int argc,char **argv)int main(void)

  2. 应避免使用以 _ 开头的标识符,除了极少数例外,reserved for the implementation

  3. main 末尾的
  4. exit(0) 在很大程度上是不必要的,因为 main 将隐式 return 0; 如果它达到其终止 }(自 C99 ).

  5. sizeof (char)guaranteed to be 1

  6. 您不需要强制转换 malloc 的返回值,因为 void * 可以安全且隐式地转换为任何其他指针类型。投射返回值是 considered a bad practice

  7. 正如评论中指出的,if (dest_string[le - 1] != '\n') 将在第一次迭代时访问 dest_string[-1],这是越界的。这是undefined behavior。当然,这也适用于涉及 source_string 的循环。

  8. 您需要检查 *alloc 函数是否失败,通过测试它们的返回值是否为 NULL。不能盲目的重新赋值realloc的返回,因为在失败的情况下,原来的指针仍然有效,迟早要free原来的指针。

  9. 另一方面,如果 realloc 成功,则应认为先前的指针值无效。虽然内存块的基地址可能没有改变是真的,但如果不先检查,你就无法知道这一点,而且测试它们是否相同是毫无意义的。如果返回值不是 NULL,只需使用该指针。

  10. 你需要测试 getchar 是否返回文件结束标记(EOF),否则,如果它发生了,你将循环直到用完记忆。

您没有向我们展示任何 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;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...