C语言 为什么 getline 的第一个参数是指向指针“char**”而不是“char*”的指针?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5744393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:27:28  来源:igfitidea点击:

Why is the first argument of getline a pointer to pointer "char**" instead of "char*"?

cfunctiongcc

提问by ct586

I use getlinefunction to read a line from STDIN.

我使用getline函数从STDIN.

The prototype of getlineis:

原型getline是:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

I use this as a test program which get from http://www.crasseux.com/books/ctutorial/getline.html#getline

我将此用作从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;
}

This works fine.

这工作正常。

My doubts are?

我的疑问是?

  1. Why use char **lineptrinstead char *lineptras a parameter of function getline?

  2. Why it is wrong when I use the following code:

    char **my_string;
    bytes_read = getline(my_string, &nbytes, stdin); 
    
  3. I am confused with *and &.

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

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

    char **my_string;
    bytes_read = getline(my_string, &nbytes, stdin); 
    
  3. 我对*和感到困惑&

Here is part of warnings:

这是警告的一部分:

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 *'

I use GCC version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5).

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

回答by ThisSuitIsBlackNot

Why use char **lineptrinstead of char *lineptras a parameter of function getline?

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

Imagine the prototype for getlinelooked like this:

想象一下它的原型getline是这样的:

ssize_t
getline(char *line, size_t n, FILE *stream);

And you called it like this:

你这样称呼它:

char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(buffer, len, stdin);

Before calling getline, bufferis null:

调用之前getlinebuffer为空:

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

When getlineis called, linegets a copy of bufferbecause function arguments are passed by value in C. Inside getline, we no longer have access to buffer:

getline被调用时,line获取 的副本,buffer因为函数参数在 C 中是按值传递的。在 内部getline,我们不再可以访问buffer

+------+
|buffer+-------> NULL
+------+          ^
                  |
+------+          |
| line +----------+
+------+

getlineallocates some memory with mallocand points lineto the beginning of the block:

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

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

+------+        +---+---+---+---+---+
| line +------->+   |   |   |   |   |
+------+        +---+---+---+---+---+

After getlinereturns, we no longer have access to line:

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

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

And we're right back where we started. We can't re-point bufferto the newly-allocated memory inside getlinebecause we only have a copy of buffer.

我们又回到了起点。我们不能重新指向buffer里面新分配的内存,getline因为我们只有buffer.



The prototype for getlineis actually:

的原型getline实际上是:

ssize_t
getline(char **lineptr, size_t *n, FILE *stream);

And you call it like this:

你这样称呼它:

char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(&buffer, &len, stdin);

&bufferreturns a pointer to buffer, so we have:

&buffer返回一个指向 的指针buffer,所以我们有:

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

When getlineis called, lineptrgets a copy of &bufferbecause C is call-by-value. lineptrpoints to the same place as &buffer:

getline被调用时,lineptr得到一个副本,&buffer因为 C 是按值调用的。lineptr指向与 相同的地方&buffer

+-------+        +------+
|&buffer+------->+buffer+-------> NULL
+-------+        +---+--+
                     ^
+-------+            |
|lineptr+------------+
+-------+

getlineallocates some memory with mallocand points the pointee of lineptr(i.e. the thing lineptrpoints to) at the beginning of the block:

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

+-------+        +------+        +---+---+---+---+---+
|&buffer+------->+buffer+------->+   |   |   |   |   |
+-------+        +---+--+        +---+---+---+---+---+
                     ^
+-------+            |
|lineptr+------------+
+-------+

After getlinereturns, we no longer have access to lineptr, but we can still access the newly-allocated memory via buffer:

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

+-------+        +------+        +---+---+---+---+---+
|&buffer+------->+buffer+------->+   |   |   |   |   |
+-------+        +---+--+        +---+---+---+---+---+

回答by John Carter

Because getline()will allocate the memory for you if you pass in a pointer to a null pointer.

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

From the man page:

手册页

getline() reads an entire line from stream, storing the address of the buffer containing the text into *lineptr. The buffer is null-terminated and includes the newline character, if one was found.

If *lineptr is NULL, then getline() will allocate a buffer for storing the line, which should be freed by the user program. (In this case, the value in *n is ignored.)

getline() 从流中读取整行,将包含文本的缓冲区的地址存储到 *lineptr 中。缓冲区以空字符结尾并包含换行符(如果找到的话)。

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

You need to pass in a char**(ie a pointer to a pointer to a char) so that the function is able to update the value of the char*that it points to.

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

You could have used:

你可以使用:

char *my_string = NULL;  // getline will alloc

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

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

Don't forget that if you do this you're responsible for free()-ing the memory allocated by getline().

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

回答by TartanLlama

Therefromhere's answer is correct for your first question. Check the manpage in future, it has the information you need.

Therefromhere 的答案对您的第一个问题是正确的。以后检查联机帮助页,它包含您需要的信息。

Your second line doesn't work because the pointer isn't initialised. If you want to do that, you'd need to write:

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

char **my_string = malloc(sizeof(char**))

Essentially, when you are creatinga variable, * means a pointer, when you are referencinga variable, it means dereference the pointer (get what the pointer points to). & means "The pointer which points to this".

本质上,当你创建一个变量时,* 意味着一个指针,当你引用一个变量时,它意味着取消引用指针(获取指针指向的内容)。& 表示“指向 this 的指针”。

回答by user2548100

Having taken over some legacy code at my new gig, I think I should offer a caution against calling calloc and returning a pointer-pointer. It should work, but it obscures how getline() operates. The & operator makes it clear that you are passing the address of the pointer you got back from malloc(), calloc(). While technically identical, declaring foo as char **foo, instead of char *foo, and then calling getline(foo,,) instead of getline(&foo,,) obscures this important point.

在我的新演出中接管了一些遗留代码后,我认为我应该警告不要调用 calloc 并返回一个指针指针。它应该可以工作,但它掩盖了 getline() 的操作方式。& 运算符清楚地表明您正在传递从 malloc()、calloc() 返回的指针的地址。虽然技术上相同,但将 foo 声明为 char **foo,而不是 char *foo,然后调用 getline(foo,,) 而不是 getline(&foo,,) 掩盖了这一重要点。

  1. getline() allows you to allocate storage and pass getline() a pointer to the pointer that malloc(), calloc() returns to you, which you assign to your pointer. Eg:

    char *foo = calloc(size_t arbitrarily_large, 1);

  2. it is possible to pass it &foo=NULL, in which case it will do a blind allocation of storage for you by quietly calling malloc(), calloc(), hidden from view.

  3. char *foo, **p_foo=&foo would also work. Then call foo = calloc(size_t, size_t), and then call getline(p_foo,,); I think getline(&foo,,) is better.

  1. getline() 允许您分配存储并将 getline() 传递给 malloc(), calloc() 返回给您的指针的指针,您将其分配给您的指针。例如:

    char *foo = calloc(size_t arbitrarily_large, 1);

  2. 可以将它传递给 &foo=NULL,在这种情况下,它会通过悄悄调用 malloc()、calloc() 为您盲分配存储,隐藏在视图中。

  3. char *foo, **p_foo=&foo 也可以。然后调用foo = calloc(size_t, size_t),再调用getline(p_foo,,); 我认为 getline(&foo,,) 更好。

Blind allocations are very bad, and an invitation to problematic memory leaks, because nowhere in YOUR code are you calling malloc(), calloc(), so you, or someone who later is tasked with maintaining your code, won't know to free() the pointer to that storage, because some function you called allocates memory without you knowing it (except for reading the function description and understanding that it's doing a blind allocation).

盲目分配非常糟糕,并且会导致有问题的内存泄漏,因为您在代码中没有任何地方调用 malloc()、calloc(),因此您或后来负责维护代码的人不会知道要释放() 指向该存储的指针,因为您调用的某些函数会在您不知情的情况下分配内存(除了阅读函数描述并了解它正在执行盲目分配)。

Since getline() will realloc() the memory your call to malloc(), calloc() provided if it's too small, it's best to just allocate your best guess as to the required storage with a call to calloc(), and make it clear what the pointer char *foo is doing. I don't believe getline() does anything with storage so long as that you have calloc()d is sufficient.

由于 getline() 将重新分配 () 您对 malloc() 的调用的内存,如果 calloc() 太小,则提供的内存,最好通过调用 calloc() 分配您对所需存储的最佳猜测,并使其清除指针 char *foo 正在做什么。我不相信 getline() 对存储做任何事情,只要你有 calloc()d 就足够了。

Keep in mind that the value of your pointer may get changed if getline() has to call realloc() to allocate more storage, as the new storage probably WILL be from a different location on the heap. IE: if you pass &foo, and foo's address is 12345, and getline() realloc()s your storage, and in a new location, foo's new address might be 45678.

请记住,如果 getline() 必须调用 realloc() 来分配更多存储空间,则指针的值可能会更改,因为新存储空间可能来自堆上的不同位置。IE:如果你传递 &foo,foo 的地址是 12345,getline() realloc()s 你的存储,在一个新的位置,foo 的新地址可能是 45678。

This isn't an arguement against doing your own call to calloc(), because if you set foo=NULL, you're guaranteedthat getline() will have to call realloc().

这并不是反对自己调用 calloc(),因为如果设置 foo=NULL,则保证getline() 必须调用 realloc()。

In summary,make a call to calloc() with some good guess as to size, which will make it obvious to anyone reading your code that memory IS BEING ALLOCATED which must be free()d, no matter what getline() does or doesn't do later.

总而言之,调用 calloc() 并对大小进行一些很好的猜测,这将使任何阅读您的代码的人都清楚内存正在被分配,该内存必须是 free()d,无论 getline() 做什么或不做什么以后不做。

if(NULL == line) {
     // getline() will realloc() if too small
    line = (char *)calloc(512, sizeof(char));
}
getline((char**)&line, (size_t *)&len, (FILE *)stdin);

回答by Sfou

Why use char **lineptr instead char *lineptr as a parameter of function getline?

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

char **lineptris used because getline()asks for the adress of the pointer that points to where the string will be stored.
You would use char *lineptrif getline()expected the pointer itself(which wouldn't work, see why in ThisSuitIsBlackNot's answer)

char **lineptr之所以使用,是因为getline()要求提供指向字符串存储位置的指针的地址。如果需要指针本身,
您将使用它(这不起作用,请参阅 ThisSuitIsBlackNot 的答案中的原因) char *lineptrgetline()

Why it is wrong when I use the following code:
char **my_string; bytes_read = getline(my_string, &nbytes, stdin);

当我使用以下代码时为什么会出错:
char **my_string; bytes_read = getline(my_string, &nbytes, stdin);

The following would work:

以下将起作用:

char *my_string;
char **pointer_to_my_string = &my_string;
bytes_read = getline(my_string, &nbytes, stdin);

I am confused with * and &.

我对 * 和 & 感到困惑。

The *has a double meaning.
When used in a declaration of a pointer, e.g. a pointer to char, it means that you want a pointer to char instead of a char.
When used elsewhere, it gets the variable at which a pointer points.

*有双重意义。
当在指针声明中使用时,例如指向 char 的指针,这意味着您需要指向 char 而不是 char 的指针。
在别处使用时,它获取指针指向的变量。

The &gets the address in memory of a variable(what pointers were created to hold as a value)

&一个变量的内存获取地址(创建什么指针保持数值)

char letter = 'c';
char *ptr_to_letter = &letter;
char letter2 = *ptr_to_letter;
char *ptr2 = &*ptr_to_letter; //ptr2 will also point to letter

&*ptr_to_lettermeans give me the address(&) of the variable at which ptr_to_letterpoints(*), and is the same as writtingptr_to_letter
You can think of *as the opposite of &, and that they cancel each other.

&*ptr_to_letter意思是给我&变量的地址( ),ptr_to_letter点( *),和写ptr_to_letter
你可以认为是*相反的&,它们相互抵消。