Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
652 views
in Technique[技术] by (71.8m points)

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

I use getline function to read a line from STDIN.

The prototype of getline is:

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

#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 **lineptr instead char *lineptr as 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 &.

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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

Imagine the prototype for getline looked like this:

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, buffer is null:

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

When getline is called, line gets a copy of buffer because function arguments are passed by value in C. Inside getline, we no longer have access to buffer:

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

getline allocates some memory with malloc and points line to the beginning of the block:

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

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

After getline returns, we no longer have access to line:

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

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


The prototype for getline is actually:

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);

&buffer returns a pointer to buffer, so we have:

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

When getline is called, lineptr gets a copy of &buffer because C is call-by-value. lineptr points to the same place as &buffer:

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

getline allocates some memory with malloc and points the pointee of lineptr (i.e. the thing lineptr points to) at the beginning of the block:

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

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

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...