【问题标题】:Using double pointers in C在 C 中使用双指针
【发布时间】:2022-11-14 14:10:23
【问题描述】:

我正在做一项任务,应该使用 getline 函数从终端读取用户的输入。这是我的代码:

int main(int ac, char **av)
{
        printf("Write something: \n");
        char **buf = NULL;
        size_t buf_size = 0;

        ssize_t bytes_read = getline(buf, &buf_size, stdin);
        if (bytes_read != -1)
                write(STDOUT_FILENO, buf,  buf_size);
        else
                printf("An error occured\n");
        free(buf);
        return (0);
}

从上面的代码。我的程序显示文本:发生错误。 做了一些代码重构,这就是我想出的:

int main(int ac, char **av)
{
        printf("Write something: \n");
        char *buf = NULL;
        size_t buf_size = 0;

        ssize_t bytes_read = getline(&buf, &buf_size, stdin);
        if (bytes_read != -1)
                write(STDOUT_FILENO, buf,  buf_size);
        else
                printf("An error occured\n");
        free(buf);
        return (0);
}

瞧!代码显示输入的任何内容,正是我想要的。所以我解决了我的问题。但是我想了解的是第一个代码 sn-p 有什么问题?这样做是对的吗?: char **name = "John Doe"; 或者 char **name = NULL;

我对在线编译器做了一些快速测试。这是代码:

int main() {
    // Write C code here
    char **name = "John Doe";
    printf("%p\n", name); //0x55f5f9890004
    printf("%p\n", *name); //0x656f44206e686f4a
    printf("%c\n", *name); //J
    printf("%p", "John Doe"); //0x55f5f9890004

    return 0;
}

我意识到双指针只是被视为单个字符指针。不确定我的发现是否正确。如果您能对上述主要功能给出更好的解释,那就太好了。

【问题讨论】:

  • 你需要打开编译器警告并阅读它们——然后你会被告知像char **name = "John Doe"; 这样的事情实际上是不能做和调用的未定义的行为下线
  • @UnholySheep。我在编译时使用了这些标志: gcc -Wall -Werror -pedantic 。但没有错误

标签: c pass-by-reference getline pass-by-value double-pointer


【解决方案1】:

char *buf 的情况下,getline 将转到指针buf 的内存位置并更改该地址。

char **buf = NULL; 的情况下,getline 将转到内存位置“null”并尝试更改该地址,这是无稽之谈。您实际上是对getline 撒谎并告诉它您在内存位置“null”存储了一个指针。

至于char **name = "John Doe";,它违反了 C 的赋值规则,任何事情都可能发生,因为代码不是有效的 C。包括“似乎一直正常工作,直到几年后在现场生产代码中发生神秘崩溃”。您可能希望通过例如应用What compiler options are recommended for beginners learning C? 将臭鼬从该在线编译器中取出

【讨论】:

    【解决方案2】:

    C 中没有“双指针”,因此您不能使用它们。

    但是对于任何类型 T,您都可以创建一个类型“指向 T 的指针”。如果 T 也是指针类型,情况也是如此。那是指向指针的指针。不是“双指针”。如果您将 char** 视为“双指针”,您将永远感到困惑。

    【讨论】:

      【解决方案3】:

      当您想更改函数中的变量时,您需要通过引用传递它。否则,该函数将处理用作参数表达式的原始对象值的副本,并且更改值的副本不会影响原始对象的值。

      在 C 中,通过引用传递意味着通过指向对象的指针间接传递对象。

      因此,取消引用指针,函数将直接访问原始对象并可以更改它。

      在这段代码中

          char *buf = NULL;                                                                                                                                       
          size_t buf_size = 0;                                                                                                                                    
                                                                                                                                                                  
          ssize_t bytes_read = getline(&buf, &buf_size, stdin); 
      

      您希望指针buf 指向函数getline 中读取的字符串。所以你需要通过引用将它传递给函数,就像你传递另一个变量buf_size一样。

      如果你会写

          char **buf = NULL;                                                                                                                                       
          size_t buf_size = 0;                                                                                                                                    
                                                                                                                                                                  
          ssize_t bytes_read = getline(buf, &buf_size, stdin);   
      

      然后函数本身将尝试取消引用导致未定义行为的空指针buf

      至于这个声明

      char **name = "John Doe";
      

      那么编译器应该发出声明错误的消息。用作初始值设定项的字符串文字被隐式转换为指向其char * 类型的第一个元素的 tp 指针。但是初始化变量的类型为char **,并且这些指针类型之间没有隐式转换。

      此外,转换说明符%s 需要char * 类型的参数,而不是char ** 类型。

      所以你必须写

      char *name = "John Doe";
      

      或者因为您可能不会更改字符串文字,所以最好编写如下声明

      const char *name = "John Doe";
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 2013-03-31
        • 1970-01-01
        • 2012-04-20
        • 2019-04-20
        • 1970-01-01
        相关资源
        最近更新 更多