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?
Why use char **lineptr
instead char *lineptr
as a parameter of function getline
?
Why it is wrong when I use the following code:
char **my_string; bytes_read = getline(my_string, &nbytes, stdin);
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).
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.
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.
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.
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.
Why use
char **lineptr
instead ofchar *lineptr
as a parameter of functiongetline
?
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+------->+ | | | | | +-------+ +---+--+ +---+---+---+---+---+
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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With