【问题标题】:Copy string in C dynamic [closed]在C动态中复制字符串[关闭]
【发布时间】:2018-02-02 16:42:34
【问题描述】:


我有两个版本的 C 代码。第一个有效,但第二个无效。
第二个的输出是分段错误,但我不知道为什么。
也许有人可以解释我的错误?我真的很感激。

这行得通:

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

void stringcpy(const char*, char*);

    int main() {

        const char * original = "C is fun.";
        int size = sizeof(original) / sizeof(char*);
        copy = (char*)malloc(sizeof(char) * 11 + 1);

        stringcpy(original, copy);
        printf("%s\n", copy);

        free(copy);

        return 0;
    }

    void stringcpy(const char* original, char* copy) {

        int i;
        for(i = 0; *(original + i) != '\0'; i++) {
            *(copy + i) = *(original + i);
        }
        *(copy + i) = '\0';
    }

这不起作用:

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

void stringcpy(const char*, char*);

int main() {

    const char * original = "C is fun.";

    char * copy;
    stringcpy(original, copy);
    printf("%s\n", copy);

    free(copy);

    return 0;
}

void stringcpy(const char* original, char* copy) {

    int size = sizeof(original) / sizeof(char*);
    copy = (char*)malloc(sizeof(char) * size + 1);

    int i;
    for(i = 0; *(original + i) != '\0'; i++) {
        *(copy + i) = *(original + i);
    }
    *(copy + i) = '\0';
}

【问题讨论】:

  • 仅供参考,C 中的参数是按值传递的。含义:函数中的copy = ... 对调用者没有任何意义。考虑一下。不相关的don't cast malloc in C programs.
  • 变量original是一个指针。在指针上执行sizeof 可以得到 pointer 的大小,而不是它所指向的大小。如果您想要字符串的长度,请使用strlen
  • 另外你还是用了sizeof(array) / sizeof(array[0]) 成语错误。
  • @Someprogrammerdude 为什么走错路了?

标签: c string malloc


【解决方案1】:
int size = sizeof(original) / sizeof(char*);

sizeof 应用于此处的指针而不是数组。这不会返回它指向的字符串的大小。 strlen 是您应该在这里寻找的那个。用这个替换上面的行(size确定的解决方案

int size = strlen(original); // better to use `size_t`

现在发生了什么 - 字符串文字是一个 char 数组,它衰减为指向第一个元素的指针,并且正在分配该指针值 - 您在其上应用了 sizeof。这里没有阵列的痕迹。要获取数组可以容纳的元素数量,您必须传递数组本身而不是指针。

另一件事是 C 是按值传递 - 所以这里要保留更改,要么将指针传递给指针,要么从函数传递分配的内存地址。

sizeof(char)1 所以你不需要显式地写 - 你可以简单地写

copy = malloc(size + 1);

代码:

stringcpy(original, &copy);

void stringcpy(const char* original, char** copy) {

    int size = strlen(original);
    *copy = malloc(size + 1);

    int i;
    for(i = 0; original[i] != '\0'; i++) {
        (*copy)[i] = original[i];
    }
    (*copy)[i] = '\0';
}

我通过将指针变量的地址传递给另一个函数,向您展示了问题的解决方案。或者(自己尝试)您可以从函数返回分配的内存块的地址并将其分配给copy。这也可以。

编辑:如果您不允许更改函数签名,那么是的,除非您像之前在 case-1 中所做的那样将分配的内存提供给 copy,否则这是不可能的。

实现正确行为的另一种方法是这样做

char* stringcpy(const char* original) {

    int size = strlen(original) ;
    char* copy = malloc(size + 1);

    int i;
    for(i = 0; original[i] != '\0'; i++) {
        copy[i] = original[i];
    }
    copy[i]=0;
    return copy;
}

并像这样使用它

copy = stringcpy(original);

这个答案中省略了几件事:

  • 始终检查 malloc 的返回值 - 如果它返回 NULL,您不会取消对它的引用。

  • 不要将malloc - char* 的返回类型强制转换为void* 隐式转换。

  • 使用完动态分配的内存后释放它。

【讨论】:

  • 感谢您的回答。但这并没有解决问题。
  • @AmirKhan.: 你用过strlen?
  • 是的,我做到了。没有任何改变。
  • @AmirKhan.: 你需要将指针传递给指针
  • 是还是不是?我很困惑。
【解决方案2】:

您在函数内部分配的内存是从堆中分配的。当您退出函数时,该内存会返还给系统,因此在您返回时不再分配。

【讨论】:

  • 内存没有“归还给系统”,而是泄露,这在实践中可能会更糟,但仍然存在问题。除非进程实际终止,否则堆分配永远不会在没有程序干预的情况下退还。
  • 那么唯一的方法是第一个代码?我不允许更改函数参数。
  • @AmirKhan 如果您无法更改参数类型,那么期望必须是提供的“目标”参数已经填充了一个引用足够大的内存的地址接受复制操作。我在这里松散地使用“必须”,因为也可以想象任务传达不佳,或者您的解释是。它们也是可能性。
猜你喜欢
  • 2018-10-19
  • 2016-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多