【问题标题】:How to traverse through a double pointer containing an array of strings?如何遍历包含字符串数组的双指针?
【发布时间】:2021-11-14 13:45:07
【问题描述】:
// Online C compiler to run C program online
#include <stdio.h>
#include <stdlib.h>

char* word(char w[]) {
    char *temp = w;
    return temp;
}

char** tokens() {
    char *one = word("One");
    char *two = word("two");
    char *three = word("three");
    char *four = word("four");
    char *five = word("five");
    char *six = word("six");
    char *seven = word("seven");
    char *eight = word("eight");
    char *nine = word("nine");
    char *ten = word("ten");
    char *eleven = word("ten");
    char *twelve = word("ten");
    char *thirteen = word("ten");
    
    char *words[13];
    
    words[0] = one;
    words[1] = two;
    words[2] = three;
    words[3] = four;
    words[4] = five;
    words[5] = six;
    words[6] = seven;
    words[7] = eight;
    words[8] = nine;
    words[9] = ten;
    words[10] = eleven;
    words[11] = twelve;
    words[12] = thirteen;
    
    char **pp = words;
    return pp;
}

int main() {
    // Write C code here
    char **pp = (char **)malloc(13 * sizeof(char));
    
    pp = tokens();
    
    for (int i = 0; i < 12; i++) {
        printf("%s\n", *pp);
        *pp++;
    }
    // for (; *pp; *pp++) {
    //     printf("%s\n", *pp);
    // }
    
    return 0;
}

我希望代码打印 tokens() 方法中包含的每个单词。但是,在 main() 的 for 循环中,它只打印:一、二、三、四、null,然后得到分段错误。如果我使用注释的 for 循环,它只会打印:一、二、三、四。我是 C 的新手,所以指针仍然很混乱。我会很感激任何帮助。谢谢。

【问题讨论】:

  • 函数word的意义何在?它除了返回它的参数之外什么都不做。
  • 我只是在测试一些我知道没有必要的东西。
  • 那就别发了。
  • @SebastianSrvn:一般来说,你应该为你的问题提供一个minimal reproducible example,这意味着应该删除所有不必要的东西。就我而言,您不必为这个问题删除它,但对未来的问题这样做会很好。否则,您的问题更有可能被否决。

标签: c pointers memory segmentation-fault


【解决方案1】:

你有很多错误:

char **pp = (char **)malloc(13 * sizeof(char));

分配内存时,要分配sizeof(&lt;oneLevelUp&gt;) * numOfElements。在这种情况下,您分配的是char**,因此“上一级”是char*。此外,no need to cast the return value of malloc。将其更改为

 char **pp = malloc(13 * sizeof(char*));

最后,最好的做法是在使用sizeof 时包含变量名。这意味着如果变量 type 发生变化,维护工作将会减少:

 char **pp = malloc(13 * sizeof(*pp));  // preferred method

*ppchar* 类型。如果您将其更改为

 int **pp = malloc(13 * sizeof(*pp));

现在*pp 自动成为int* 类型,无需将sizeof 参数从char* 更改为int*

其他问题已经在 cmets 和 answers 中得到解决。 word 基本上什么都不做,因为它只是返回传递给它的参数;这个功能肯定会得到优化。 @AndreasWenzel 的回答解释了 tokens 的问题。评价最高的答案here 有一个关于返回指向局部变量的指针的有趣轶事。

最后一点,即使 tokens 没有调用 UB,您也会/正在通过将 pp 分配给 tokens 的返回值来创建内存泄漏。

char **pp = malloc(13 * sizeof(*pp));
if (pp == NULL)
{
  // uh oh, we're out of memory, handle the error however you want. For this example, just exit
  exit(-1);
}

// uh oh, by making this assignment, pp no longer points to the memory block
// returned from `malloc`. Now that memory is reserved and nothing points to
// it. If we did this over and over, our process would continue to consume
// memory until none was left.
pp = tokens();

【讨论】:

    【解决方案2】:

    一旦函数tokens返回,数组wordslifetime就结束了。因此,函数tokens 返回指向该对象的指针是没有意义的,因为该指针将指向一个不再存在的对象。取消引用该指针将导致undefined behavior(即您的程序可能会崩溃)。

    如果您希望函数tokens 返回一个指向有效对象的指针,您必须确保words 的生命周期不会结束,例如通过使用动态内存分配(即malloc)或更改使用 static 关键字将 words 的生命周期变为静态。

    在您的情况下,最好删除函数 tokens 并在函数 main 内简单地定义变量 words,如下所示:

    static const char *const words[] = {
        "one", "two", "three", "four", "five",
        "six", "seven", "eight", "nine", "ten",
        "eleven", "twelve", "thirteen"
    };
    

    如果你真的想保留函数tokens,那么你可以这样重写:

    const char *const * tokens( void )
    {
        static const char *const words[] = {
            "one", "two", "three", "four", "five",
            "six", "seven", "eight", "nine", "ten",
            "eleven", "twelve", "thirteen"
        };
    
        return words;
    }
    

    这样,函数tokens 将返回一个指向静态分配对象的指针,该对象具有静态(无限)生命周期。

    【讨论】:

      猜你喜欢
      • 2021-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-09
      相关资源
      最近更新 更多