【问题标题】:C char array, pointers, malloc, free [closed]C char 数组,指针,malloc,免费 [关闭]
【发布时间】:2016-11-30 13:57:07
【问题描述】:

我正在尝试理解指针,我有这个简单的例子

void third(char ****msg) {
    ***msg = malloc(5 * sizeof (char));
    printf("\nthe msg in third is :%s ", ***msg);
    strcpy(***msg, "third");
    printf("\nthe msg in third after is: %s", ***msg);
    // free(***msg);
}

void change(char***msg) {
    **msg = malloc(5 * sizeof (char));
    printf("\nthe msg in change is :%s ", **msg);
    strcpy(**msg, "change");
    printf("\nthe msg in change after is: %s", **msg);
    third(&msg);
    //   free(**msg);
}

void test(char ** msg) {
    *msg = malloc(5 * sizeof (char));
    printf("\n the msg in test is: %s", *msg);

    strcpy(*msg, "test");
    printf("\nthe msg in test after is: %s\n", *msg);

    change(&msg);
    free(*msg);
}

int main(int argc, char** argv) {

    char * msg;
    test(&msg);
    printf("\nthe msg back in main is: %s", msg);
}

我可以说它工作正常,但你能告诉我何时以及如何释放分配的内存,因为如果我从函数更改中删除 /// 第三个并运行它,我会遇到错误。有没有办法在每个函数的第一个打印语句中获取消息的内容 - 请参阅 otuput:

the msg in test is: 
the msg in test after is: test
the msg in change is :0�� 
the msg in change after is: change
the msg in third is :P�� 
the msg in third after is: third
the msg back in main is: 

有没有办法让味精发生变化是:测试然后 第三个味精是:改变

【问题讨论】:

  • 简单例子?有四个开始?你已经超越了成为一名 t(h)ree-star 程序员。
  • 哇!你是我看到的第一个 4 星 C 程序员!您知道成为 3 星 C 程序员已经不是恭维了,是吗?
  • @SouravGhosh:什么是-star程序员?有人住在树上吗? ;-))
  • @Olaf 已编辑...但确实如此,如果我继续编写这样的代码,最安全的地方(避免维护者)将只是一个树屋。 ;-)
  • 去掉change()和third(),从头开始分析。

标签: c pointers char malloc free


【解决方案1】:

忘记那个程序吧,它有太多问题了:

  • 您不需要多级间接。两层就够了。如果该函数需要更改地址,只需将指针传递给下一个函数即可。
  • 您尝试在字符串初始化之前打印它。
  • 释放后尝试使用该字符串。
  • 在不清理旧内容的情况下重复调用 malloc 会造成内存泄漏。请改用 realloc。
  • 您分配了不正确的内存量,因此数组不够大,无法容纳您 strcpy 到其中的字符串。另请注意,您需要为空终止符分配足够的空间。

等等。这是一个固定版本:

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

void third(char** msg) {
    const char str[] = "third";

    *msg = realloc(*msg, sizeof(str));
    printf("the msg in third is :%s\n", *msg);

    strcpy(*msg, str);
    printf("the msg in third after is: %s\n", *msg);
}

void change(char** msg) {
    const char str[] = "change";

    *msg = realloc(*msg, sizeof(str));
    printf("the msg in change is :%s\n", *msg);

    strcpy(*msg, str);
    printf("the msg in change after is: %s\n", *msg);

    third(msg);
}

void test(char** msg) {
    const char str[] = "test";

    *msg = malloc(sizeof(str));
    printf("the msg in test is just garabage at this point, no need to print it.\n");

    strcpy(*msg, str);
    printf("the msg in test after is: %s\n", *msg);

    change(msg);
}

int main(int argc, char** argv) {

    char* msg;
    test(&msg);
    printf("the msg back in main is: %s\n", msg);

    free(msg);
}

【讨论】:

  • 太棒了!现在我明白了。这是否适用于其他数据类型,例如整数或整数 [] ?
  • @JohnRichards 数组的数据类型无关紧要,但用作字符串的char 数组是一种特殊情况,因为它们需要以空值结尾。声明 const char str[] = "test"; 时,您会得到一个由 4 个字符 + 1 个空终止符组成的数组。这就是sizeof(str) 起作用的原因。
【解决方案2】:

在现实生活中,避免使用尽可能多的“星号”(即间接数)。此外,您的代码有几个问题涉及undefined behavior (UB)

void third(char ****msg) {
    ***msg = malloc(5 * sizeof (char));
    printf("\nthe msg in third is :%s ", ***msg);// Don't do that, ***msg is not intialize => UB
    strcpy(***msg, "third"); // Don't do that => ***msg has 5 bytes, and you copy 6 char => UB
    printf("\nthe msg in third after is: %s", ***msg);
    // free(***msg);
}

void change(char***msg) {
    **msg = malloc(5 * sizeof (char));
    printf("\nthe msg in change is :%s ", **msg);// Don't do that, **msg is not intialize => UB
    strcpy(**msg, "change"); // Don't do that => **msg has 5 bytes, and you copy 7 char => UB
    printf("\nthe msg in change after is: %s", **msg);
    third(&msg);
    //   free(**msg);
}

void test(char ** msg) {
    *msg = malloc(5 * sizeof (char));
    printf("\n the msg in test is: %s", *msg); // Don't do that, *msg is not intialize => UB

    strcpy(*msg, "test");
    printf("\nthe msg in test after is: %s\n", *msg);

    change(&msg);
    free(*msg);
}

int main(int argc, char** argv) {

    char * msg;
    test(&msg);
    printf("\nthe msg back in main is: %s", msg); //UB => you use freed variable
}

改正了这个多来源的UB后,还是一个不好的设计:free函数的使用

根据您使用...的指针的事实,当您在函数内执行malloc 时,您还修改了调用者的指针。试着运行一下看看:

void first(char **t)
{
    *t = malloc(5*sizeof(char));
}

int main(int argc, char * argv[])
{
    char * t = NULL;
    printf("%p\n", t);
    first(&t);
    printf("%p\n", t);
    return 0;
}

它产生(demo):

(nil)
 0x995f008 (or another address)

所以当你在test 中释放时,你释放了在third 中分配的内存


最后,正如评论中已经提到的,只有2星就足够了:

void third(char **msg) {
    free(*msg); // Free before allocate and change address stored in pointer
    *msg = malloc(6 * sizeof (char));
    strcpy(*msg, "third");
    printf("\nthe msg in third after is: %s", *msg);
}

void change(char **msg) {
    free(*msg); // Free before allocate and change address stored in pointer
    *msg = malloc(7 * sizeof (char));
    strcpy(*msg, "change");
    printf("\nthe msg in change after is: %s", *msg);
    third(msg);
}

void test(char ** msg) {
    *msg = malloc(5 * sizeof (char));

    strcpy(*msg, "test");
    printf("\nthe msg in test after is: %s\n", *msg);

    change(msg);
}

int main(int argc, char** argv) {

    char * msg;
    test(&msg);
    printf("\nthe msg back in main is: %s", msg);
    free(msg); // Deallocate memory ONLY when you don't need it anymore
    msg = NULL; // Good practice, set to NULL freed pointer to inform that no more memory are allocated
}

【讨论】:

  • 好的,我明白了。那么释放内存呢。测试中的免费是否足够?
  • @JohnRichards 我认为我的编辑回答了你的问题
猜你喜欢
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
  • 1970-01-01
  • 2021-01-26
  • 1970-01-01
  • 1970-01-01
  • 2021-04-03
相关资源
最近更新 更多