C语言 当我打印修改后的字符串从函数返回后,它显示给我垃圾值


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) = '';
    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) = '';
    _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] != '')
    {
        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  ) = '';
    puts(dest_string);
    return ;
}

这里有许多需要注意的问题,有大有小,不分先后:

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

  2. 应该避免以_开头的标识符,因为除了极少数例外,它们是为实现保留的。

  3. exit(0)位于main的末尾,这在很大程度上是不必要的,因为如果main到达其终止},则会隐式地显示return 0;(从C99开始)。

  4. sizeof (char)保证是1

  5. 您不需要强制转换malloc的返回值,因为void *可以安全地隐式转换为任何其他指针类型。强制转换返回值被认为是不好的做法。

  6. 正如评论中指出的,if (dest_string[le - 1] != 'n')将在第一次迭代时访问dest_string[-1],这是越界的。这是未定义的行为。当然,对于包含source_string的循环也是如此。

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

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

  9. 您需要测试getchar是否返回文件结束标记(EOF),否则,如果它发生,您将循环直到内存耗尽。

您没有向我们显示任何头文件,所以我不得不假设您没有包含它们。你需要

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

每当你重复自己的时候,这几乎总是一个信号,你应该把这些部分重新组合成某种形式的抽象。在本例中,您编写的用于从stdin构建字符串的相同代码部分应该简化为一个函数。

因为你没有错误检查realloc,我们必须假设它总是成功的。因此,列表中的#8告诉我们,不能可靠地假设main中的dest_string在调用_concatenate之后指向有效内存,其中可能已经移动了位于该指针上的数据,并释放了旧数据

如果没有足够的空间来扩大ptr所指向的内存分配,realloc()创建一个新的分配,复制ptr所指向的旧数据,尽可能多地适合新的分配,释放旧的分配,并返回一个指向已分配内存的指针。

,因此puts(dest_string)可能访问无效或未初始化的内存,free(dest_string)可能导致双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, 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;
}
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] = '';
    return buf;
}

最新更新