Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

function

gcc

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

like image 492
ct586 Avatar asked Apr 21 '11 12:04

ct586


People also ask

Why does Asprintf take a pointer?

The goal with asprintf(...) is to pass in a location for the function to store some information. It is a pointer which points an another pointer. char is a variable which can hold one byte. The reason why *char is used is to hold multiple characters representing a string.

How does getline work in c?

The getline method reads a full line from a stream, such as a newline character. To finish the input, use the getline function to generate a stop character. The command will be completed, and this character will be removed from the input.

Is Getline safe in C?

No. It is not safe. Code instead could initialize string = NULL, nbytes = 0 within this function and free string when done. As coded, the prior values of nbytes and my_string are needed to be specified as well the updated values after the getline() call needs to update boxdim() calling arguments.

Is Getline standard input?

The getline() function debuts at Line 20. It uses the address of buffer , bufsize , and then stdin for standard input. Because variable characters is a size_t variable type, the %zu placeholder is used in the printf() function at Line 21.


2 Answers

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+------->+   |   |   |   |   | +-------+        +---+--+        +---+---+---+---+---+ 
like image 84
ThisSuitIsBlackNot Avatar answered Sep 30 '22 09:09

ThisSuitIsBlackNot


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

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

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.

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

like image 29
John Carter Avatar answered Sep 30 '22 09:09

John Carter