为什么getline的第一个参数指向指针"char**"而不是"char*"?

ct5*_*586 27 c gcc function

我用getline函数来读取一行STDIN.

原型getline是:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);
Run Code Online (Sandbox Code Playgroud)

我使用它作为测试程序,来自http://www.crasseux.com/books/ctutorial/getline.html#getline

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

int main(int atgc, char *argv[])
{
    int bytes_read = 1;
    int nbytes = 10;
    char *my_string;

    my_string = (char *)malloc(nbytes+1);

    puts("Please enter a line of text");

    bytes_read = getline(&my_string, &nbytes, stdin);

    if (bytes_read == -1)
    {
        puts ("ERROR!");
    }
    else
    {
        puts ("You typed:");
        puts (my_string);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这很好用.

我的怀疑是?

  1. 为什么使用char **lineptr而不是char *lineptr作为函数中的参数getline

  2. 使用以下代码时为什么会出错:

    char **my_string;
    bytes_read = getline(my_string, &nbytes, stdin); 
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我很困惑*&.

以下是警告的一部分:

testGetline.c: In function ‘main’: 
testGetline.c:34: warning: pointer targets in passing argument 2 of  
  ‘getline’ differ in signedness 
/usr/include/stdio.h:671: 
  note: expected ‘size_t * __restrict__’ but argument is of type ‘int *’  
testGetline.c:40: warning: passing argument 1 of ‘putchar’ makes integer 
  from pointer without a cast 
/usr/include/stdio.h:582: note: expected ‘int’ but argument is of 
  type ‘char *’
Run Code Online (Sandbox Code Playgroud)

我使用GCC版本4.4.5(Ubuntu/Linaro 4.4.4-14ubuntu5).

Thi*_*Not 27

为什么要使用char **lineptr而不是char *lineptr作为函数的参数getline

想象一下原型getline看起来像这样:

ssize_t
getline(char *line, size_t n, FILE *stream);
Run Code Online (Sandbox Code Playgroud)

你这么称呼它:

char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(buffer, len, stdin);
Run Code Online (Sandbox Code Playgroud)

在调用之前getline,buffer为null:

+------+
|buffer+-------> NULL
+------+
Run Code Online (Sandbox Code Playgroud)

getline调用时,line获取一个buffer因为函数参数的副本通过C中的值传递.在内部getline,我们不再有权访问buffer:

+------+
|buffer+-------> NULL
+------+          ^
                  |
+------+          |
| line +----------+
+------+
Run Code Online (Sandbox Code Playgroud)

getline分配一些内存malloc并指向line块的开头:

+------+
|buffer+-------> NULL
+------+

+------+        +---+---+---+---+---+
| line +------->+   |   |   |   |   |
+------+        +---+---+---+---+---+
Run Code Online (Sandbox Code Playgroud)

之后getline的回报,我们不再有机会获得line:

+------+
|buffer+-------> NULL
+------+
Run Code Online (Sandbox Code Playgroud)

我们回到了我们开始的地方.我们无法重新指向buffer新分配的内存,getline因为我们只有一个副本buffer.


原型getline实际上是:

ssize_t
getline(char **lineptr, size_t *n, FILE *stream);
Run Code Online (Sandbox Code Playgroud)

你这样称呼它:

char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(&buffer, &len, stdin);
Run Code Online (Sandbox Code Playgroud)

&foo返回指针foo,所以我们有:

+-------+        +------+
|&buffer+------->+buffer+-------> NULL
+-------+        +---+--+
Run Code Online (Sandbox Code Playgroud)

getline被调用时,lineptr得到的副本&buffer,因为C是调用-值.lineptr指向同一个地方&buffer:

+-------+        +------+
|&buffer+------->+buffer+-------> NULL
+-------+        +---+--+
                     ^
+-------+            |
|lineptr+------------+
+-------+
Run Code Online (Sandbox Code Playgroud)

getline分配一些内存malloc并指向块开头的指针lineptr(即lineptr指向的东西):

+-------+        +------+        +---+---+---+---+---+
|&buffer+------->+buffer+------->+   |   |   |   |   |
+-------+        +---+--+        +---+---+---+---+---+
                     ^
+-------+            |
|lineptr+------------+
+-------+
Run Code Online (Sandbox Code Playgroud)

之后getline的回报,我们不再有机会获得lineptr,但我们仍然可以通过访问新分配的内存buffer:

+-------+        +------+        +---+---+---+---+---+
|&buffer+------->+buffer+------->+   |   |   |   |   |
+-------+        +---+--+        +---+---+---+---+---+
Run Code Online (Sandbox Code Playgroud)


Joh*_*ter 12

因为getline()如果传入指向空指针的指针,将为您分配内存.

手册页:

getline()从流中读取整行,将包含文本的缓冲区的地址存储到*lineptr中.缓冲区以空值终止,并包含换行符(如果找到).

如果*lineptr为NULL,则getline()将分配用于存储该行的缓冲区,该缓冲区应由用户程序释放.(在这种情况下,忽略*n中的值.)

您需要传入一个char**(即指向char的指针),以便该函数能够更新char*它指向的值.

你可以使用:

char *my_string = NULL;  // getline will alloc

puts("Please enter a line of text");

bytes_read = getline(&my_string, &nbytes, stdin);
Run Code Online (Sandbox Code Playgroud)

不要忘记,如果你这样做,你负责free()分配的内存getline().


Tar*_*ama 6

对于你的第一个问题,答案是正确的.将来查看联机帮助页,它提供了您需要的信息.

您的第二行不起作用,因为指针未初始化.如果你想这样做,你需要写:

char **my_string = malloc(sizeof(char**))
Run Code Online (Sandbox Code Playgroud)

本质上,当您创建变量时,*表示指针,当您引用变量时,它意味着取消引用指针(获取指针指向的内容).&表示"指向此的指针".