Segmentation error with getline() function?
I'm learning C on the terminal on Linux, and I did a small game in text, so everything is functioning (especially my big loop for if the player want to restart the game), and I just add a dump "Enter your pseudo" at the beginning.
It doesn't function when I enter it, it says me
Segmentation Error , core dumped
Here is all the code, the most important is the first lines because all the rest is functioning perfectly:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
int main (void) {
// déclaration des variables
bool essais8 = false ;
bool essais10 = false ;
bool essais12 = false;
bool essais14 = false;
bool condition = true;
bool condition_diff = false;
bool condition_recommencer = false;
bool condition_bonus1 = true;
bool condition_bonus2 = true;
bool condition_bonus3 = true;
char* buffer;
char* recommencer;
char* pseudo ;
size_t bufsize = 32;
size_t characters;
int difficulte;
int sheitan = 0;
int sheitan2 = 0;
int a;
int bonus1;
int bonus2;
int bonus3;
int ecart;
int essais;
int nb_bonus2;
srand(time(NULL));
// on récupère le pseudo du joueur
printf("Salut ! Quel est ton nom ? ");
characters = getline(&buffer,&bufsize,stdin);
pseudo = buffer;
// after this I have the segmentation errror
while (condition == true) { // Boucle de recommencement du Jeu
// here is the big game that was functioning perfectly before I add the pseudo option on top.
}
printf("Fin du programme n");
return(0);
}
c linux getline
add a comment |
I'm learning C on the terminal on Linux, and I did a small game in text, so everything is functioning (especially my big loop for if the player want to restart the game), and I just add a dump "Enter your pseudo" at the beginning.
It doesn't function when I enter it, it says me
Segmentation Error , core dumped
Here is all the code, the most important is the first lines because all the rest is functioning perfectly:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
int main (void) {
// déclaration des variables
bool essais8 = false ;
bool essais10 = false ;
bool essais12 = false;
bool essais14 = false;
bool condition = true;
bool condition_diff = false;
bool condition_recommencer = false;
bool condition_bonus1 = true;
bool condition_bonus2 = true;
bool condition_bonus3 = true;
char* buffer;
char* recommencer;
char* pseudo ;
size_t bufsize = 32;
size_t characters;
int difficulte;
int sheitan = 0;
int sheitan2 = 0;
int a;
int bonus1;
int bonus2;
int bonus3;
int ecart;
int essais;
int nb_bonus2;
srand(time(NULL));
// on récupère le pseudo du joueur
printf("Salut ! Quel est ton nom ? ");
characters = getline(&buffer,&bufsize,stdin);
pseudo = buffer;
// after this I have the segmentation errror
while (condition == true) { // Boucle de recommencement du Jeu
// here is the big game that was functioning perfectly before I add the pseudo option on top.
}
printf("Fin du programme n");
return(0);
}
c linux getline
2
None of your pointers are initialized to point at valid memory
– UnholySheep
Jan 19 at 11:10
2
@UnholySheep ... orNULL
or0
.
– alk
Jan 19 at 11:11
add a comment |
I'm learning C on the terminal on Linux, and I did a small game in text, so everything is functioning (especially my big loop for if the player want to restart the game), and I just add a dump "Enter your pseudo" at the beginning.
It doesn't function when I enter it, it says me
Segmentation Error , core dumped
Here is all the code, the most important is the first lines because all the rest is functioning perfectly:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
int main (void) {
// déclaration des variables
bool essais8 = false ;
bool essais10 = false ;
bool essais12 = false;
bool essais14 = false;
bool condition = true;
bool condition_diff = false;
bool condition_recommencer = false;
bool condition_bonus1 = true;
bool condition_bonus2 = true;
bool condition_bonus3 = true;
char* buffer;
char* recommencer;
char* pseudo ;
size_t bufsize = 32;
size_t characters;
int difficulte;
int sheitan = 0;
int sheitan2 = 0;
int a;
int bonus1;
int bonus2;
int bonus3;
int ecart;
int essais;
int nb_bonus2;
srand(time(NULL));
// on récupère le pseudo du joueur
printf("Salut ! Quel est ton nom ? ");
characters = getline(&buffer,&bufsize,stdin);
pseudo = buffer;
// after this I have the segmentation errror
while (condition == true) { // Boucle de recommencement du Jeu
// here is the big game that was functioning perfectly before I add the pseudo option on top.
}
printf("Fin du programme n");
return(0);
}
c linux getline
I'm learning C on the terminal on Linux, and I did a small game in text, so everything is functioning (especially my big loop for if the player want to restart the game), and I just add a dump "Enter your pseudo" at the beginning.
It doesn't function when I enter it, it says me
Segmentation Error , core dumped
Here is all the code, the most important is the first lines because all the rest is functioning perfectly:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
int main (void) {
// déclaration des variables
bool essais8 = false ;
bool essais10 = false ;
bool essais12 = false;
bool essais14 = false;
bool condition = true;
bool condition_diff = false;
bool condition_recommencer = false;
bool condition_bonus1 = true;
bool condition_bonus2 = true;
bool condition_bonus3 = true;
char* buffer;
char* recommencer;
char* pseudo ;
size_t bufsize = 32;
size_t characters;
int difficulte;
int sheitan = 0;
int sheitan2 = 0;
int a;
int bonus1;
int bonus2;
int bonus3;
int ecart;
int essais;
int nb_bonus2;
srand(time(NULL));
// on récupère le pseudo du joueur
printf("Salut ! Quel est ton nom ? ");
characters = getline(&buffer,&bufsize,stdin);
pseudo = buffer;
// after this I have the segmentation errror
while (condition == true) { // Boucle de recommencement du Jeu
// here is the big game that was functioning perfectly before I add the pseudo option on top.
}
printf("Fin du programme n");
return(0);
}
c linux getline
c linux getline
edited Jan 19 at 11:23
alk
58.6k763172
58.6k763172
asked Jan 19 at 11:07
ChetritChetrit
31
31
2
None of your pointers are initialized to point at valid memory
– UnholySheep
Jan 19 at 11:10
2
@UnholySheep ... orNULL
or0
.
– alk
Jan 19 at 11:11
add a comment |
2
None of your pointers are initialized to point at valid memory
– UnholySheep
Jan 19 at 11:10
2
@UnholySheep ... orNULL
or0
.
– alk
Jan 19 at 11:11
2
2
None of your pointers are initialized to point at valid memory
– UnholySheep
Jan 19 at 11:10
None of your pointers are initialized to point at valid memory
– UnholySheep
Jan 19 at 11:10
2
2
@UnholySheep ... or
NULL
or 0
.– alk
Jan 19 at 11:11
@UnholySheep ... or
NULL
or 0
.– alk
Jan 19 at 11:11
add a comment |
4 Answers
4
active
oldest
votes
You forgot to initialize buffer
. And you'll better end your printf(3) format control string with n
or else call fflush(3) before any input (since stdio(3) is buffered).
An uninitialized pointer contains garbage. Using it is undefined behavior. Be scared !
So my suggestion is to code
size_t bufsiz = 64;
char *buffer = malloc(bufsiz);
if (!buffer) { perror("malloc buffer"); exit(EXIT_FAILURE); };
and later
printf("Salut ! Quel est ton nom ?n");
characters = getline(&buffer,&bufsize,stdin);
Next time enable all warnings and debug info when compiling, so compile your code with gcc -Wall -Wextra -g
if using GCC. You would have got some warnings.
Of course, read How to debug small programs and debugging with GDB
On Linux, in your particular case, you could be interested in using readline(3) instead of getline(3).
Don't forget to read the documentation of every function that you are using (e.g. here, if it is a standard C one).
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
add a comment |
getline()
can be used in two different ways:
- Read into a buffer provided by the caller.
- Allocate memory when reading.
To use 1. initialise the pointer passed to point to valid memory and pass as well the size of the latter.
#define INITIAL_SIZE (42)
int main(void)
{
char * buffer = malloc(INITIAL_SIZE * sizeof *buffer);
size_t bufsize = INITIAL_SIZE;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
To use 2. initialise the pointer passed to NULL
and pass 0
as size.
int main(void)
{
char * buffer = NULL;
size_t bufsize = 0;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
Note: getline()
returns ssize_t
not size_t
.
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
add a comment |
'buffer' variable is pointing to some garbage memory address. You need to allocate necessary memory first, using 'malloc' function or make 'buffer' a static array, instead of pointer.
1
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to usegetline()
.
– alk
Jan 19 at 11:21
add a comment |
getline()
is a POSIX.1 function, which reads lines into dynamically allocated buffers, allowing lines of any length (limited only by the amount of available memory). It returns the number of characters read, or -1 if there is no more input, or an error occurred.
Here is one example use pattern:
char *line = NULL;
size_t size = 0;
ssize_t len;
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Do something with the input line */
}
At any point, you can release the dynamically allocated buffer using
free(line);
line = NULL;
size = 0;
The reason you want to clear the pointer to NULL and size to zero is that that way, you do not accidentally try to access the already freed memory, but you can call getline(&line, &size, handle)
to read more lines as the call will simply recognize it does not have a buffer, and will allocate a new one.
You can manipulate the dynamic data in any way you wish, if you are careful. For example:
while (1) {
char *line = NULL;
size_t size = 0;
ssize_t len;
len = getline(&line, &size, stdin);
if (len < 1) {
free(line);
break;
}
/* Do something with the contents of the line */
free(line);
}
will work, but it will be quite slow, because the C library will do at least one malloc()
call for every line read, and possibly additional realloc()
calls, depending on the line length.
The reason getline()
is written as it is, is that it allows reusing the same buffer for any number of lines. If you read files sequentially, you can reuse the same buffer. Let's look at a more complex example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
int main(int argc, char *argv)
{
unsigned long linenum;
char *line = NULL, *in, *out, *end;
size_t size = 0, n;
ssize_t len;
FILE *src;
int arg;
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.n");
if (argc < 2) {
fprintf(stderr, "n");
fprintf(stderr, "Usage: %s FILENAME [ FILENAME ... ]n", argv[0]);
fprintf(stderr, "n");
exit(EXIT_FAILURE);
}
for (arg = 1; arg < argc; arg++) {
src = fopen(argv[arg], "r");
if (!src) {
fprintf(stderr, "%s: %s.n", argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
linenum = 0;
while (1) {
len = getline(&line, &size, src);
if (len < 1)
break;
linenum++;
/* First character in the line read: */
in = line;
out = line;
/* Pointer to the end-of-string character on the line: */
end = line + len;
/* Skip all leading whitespace characters. */
while (in < end && isspace((unsigned char)(*in)))
in++;
/* Character copy loop. */
while (in < end)
if (isspace((unsigned char)(*in))) {
/* Replace consecutive whitespace characters with spaces. */
*(out++) = ' ';
do {
in++;
} while (in < end && isspace((unsigned char)(*in)));
} else {
/* Copy all other characters as-is. */
*(out++) = *(in++);
}
/* There may be a single space before out. Backtrack it, if so. */
if (out > line && out[-1] == ' ')
out--;
/* Mark the end of the string at out. */
*out = '';
/* Calculate the new length, just for output purposes. */
n = (size_t)(out - line);
/* Print the line. */
printf("%s: Line %lu: '%s' (%zu of %zd characters)n",
argv[arg], linenum, line, n, len);
}
if (!feof(src) || ferror(src)) {
fprintf(stderr, "%s: Read error.n", argv[arg]);
fclose(src);
free(line);
exit(EXIT_FAILURE);
}
if (fclose(src)) {
fprintf(stderr, "%s: Error closing file: %s.n",
argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
}
free(line);
line = NULL;
size = 0;
return EXIT_SUCCESS;
}
If we save the above as say example.c, and compile it using e.g. gcc -Wall -O2 example.c -o example
, and run the program supplying it with the names of text files as parameters, for example ./example example.c
, it will output something like
example.c: Line 1: '#define _POSIX_C_SOURCE 200809L' (31 of 33 characters)
example.c: Line 2: '#include <stdlib.h>' (19 of 20 characters)
example.c: Line 3: '#include <locale.h>' (19 of 20 characters)
example.c: Line 4: '#include <string.h>' (19 of 20 characters)
example.c: Line 5: '#include <stdio.h>' (18 of 19 characters)
example.c: Line 6: '#include <ctype.h>' (18 of 19 characters)
example.c: Line 7: '#include <errno.h>' (18 of 19 characters)
example.c: Line 8: '' (0 of 1 characters)
example.c: Line 9: 'int main(int argc, char *argv)' (32 of 33 characters)
What the program does, is simply read each specified file line by line, remove any leading and trailing whitespace on each line, and combine all consecutive whitespace into a single space. The smaller character count is the number of characters left (and shown), the larger number is the original number of chars read from the file.
Additional notes on the example program, if it happens to interest you
The
setlocale(LC_ALL, "")
call tells your C library to use the users locale (usually defined in theLANG
orLC_ALL
environment variables). This program uses only the character type definitions for the character set used by the current locale (to determine which codes are "whitespace"), so this could also be limited to that, viasetlocale(LC_CTYPE, "")
. The call will return NULL if the current locale is not supported by the C library. Usually that is because of an error in the user configuration, so it is useful to have the program warn then.The
isspace()
(and all otheris*()
functions defined in<ctype.h>
) take an unsigned character code (or EOF). Becausechar
type can be signed or unsigned, we explicitly cast the character to(unsigned char)
before supplying to the function. Consider this silly historical baggage that we just have to deal with this way.Because
line
points to the beginning of the dynamically allocated memory buffer, we must not modify it (except viarealloc()
, orfree()
and then set toNULL
). If we do modify it, any subsequentgetline()
orfree()
call using that pointer will likely freak out, and crash the program, since they really need the pointer to point to the beginning of the buffer, not just somewhere inside it.
I like using pointers (
char *in, *out, *end
) instead of indexes. Here,in
starts atline
, and goes up to but not includingline+len
, which is wheregetline()
put the end-of-string nulto indicate the end of the line. That's why I also often use a pointer named
end
to point to that. Theout
starts atline
also, but only increases when characters are kept in a line.
If you think about a row of lettered tiles, like in scrabble,
out
points to the next position you'll put a kept tile, andin
points to the next tile you get.
When
getline()
orgetdelim()
returns a zero or a negative value (orfgets()
returns NULL), it means that either there was no more data to read, or the operation failed for some other reason.
After the loop,
(!feof(src) || ferror(src))
checks if the input stream was read completely without errors. Well, rather, the inverse: the expression is true only if an error occurred, or the entire file was not read.
If I had written data to some file, say
FILE *dst
, I typically precede this test withif (fflush(dst))
test. It is true if there is an error writing the last of the data buffered by the C library to the file.
The
fclose(src)
closes the file. I personally prefer to verify its return value, because even though currently it can only fail in very specific circumstances, I as an user would definitely prefer to know if the OS had issues writing my data! The test costs basically nothing, but may be crucial for the user. I do not want any programs to "forget" telling me there was a problem, when working on my data; my data is important to me.
free(NULL)
is safe, and does nothing. (Also,realloc(NULL, size)
is equivalent tomalloc(size)
, so if you initialize a pointer to NULL, you don't need an initial malloc, you can justrealloc()
it always to the size you need.)
I suggest you play with the above code. You can even run it under ltrace (ltrace ./example example.c
) to see which standard C library calls are actually performed, and their results; or under strace (strace ./example example.c
) to see the syscalls (from the process to the OS kernel proper).
As an example, you could add say
if (linenum == 7) {
/* We skip line 7, and even destroy it! Muahhahah! */
free(line);
line = NULL;
size = 0;
continue;
}
just after the linenum++
line, to see what happens to the seventh lines of the text files. (They're skipped, and even if the buffer is released, nothing bad happens (because continue
starts the next iteration of the while loop body), as the next getline()
will just dynamically allocate a new line.
If you decide you want to keep a copy of part of the line, just calculate the length you need adding one for the end-of-string nul (), allocate that many chars for the duplicate (
sizeof (char) == 1
in C, always; so malloc() et al. take the number of chars to allocate for, really), memcpy()
the data, and add the terminating nul. For example,
char *sdup(const char *const source, const size_t length)
{
char *s;
s = malloc(length + 1);
if (!s) {
/* Either return NULL, or: */
fprintf(stderr, "sdup(): Not enough memory for %zu chars.n", length + 1);
exit(EXIT_FAILURE);
}
if (length > 0)
memcpy(s, source, length);
s[length] = '';
return s;
}
If you want the full string (up to end of string nul), you can use the POSIX.1-2008 strdup()
instead.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54266432%2fsegmentation-error-with-getline-function%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
You forgot to initialize buffer
. And you'll better end your printf(3) format control string with n
or else call fflush(3) before any input (since stdio(3) is buffered).
An uninitialized pointer contains garbage. Using it is undefined behavior. Be scared !
So my suggestion is to code
size_t bufsiz = 64;
char *buffer = malloc(bufsiz);
if (!buffer) { perror("malloc buffer"); exit(EXIT_FAILURE); };
and later
printf("Salut ! Quel est ton nom ?n");
characters = getline(&buffer,&bufsize,stdin);
Next time enable all warnings and debug info when compiling, so compile your code with gcc -Wall -Wextra -g
if using GCC. You would have got some warnings.
Of course, read How to debug small programs and debugging with GDB
On Linux, in your particular case, you could be interested in using readline(3) instead of getline(3).
Don't forget to read the documentation of every function that you are using (e.g. here, if it is a standard C one).
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
add a comment |
You forgot to initialize buffer
. And you'll better end your printf(3) format control string with n
or else call fflush(3) before any input (since stdio(3) is buffered).
An uninitialized pointer contains garbage. Using it is undefined behavior. Be scared !
So my suggestion is to code
size_t bufsiz = 64;
char *buffer = malloc(bufsiz);
if (!buffer) { perror("malloc buffer"); exit(EXIT_FAILURE); };
and later
printf("Salut ! Quel est ton nom ?n");
characters = getline(&buffer,&bufsize,stdin);
Next time enable all warnings and debug info when compiling, so compile your code with gcc -Wall -Wextra -g
if using GCC. You would have got some warnings.
Of course, read How to debug small programs and debugging with GDB
On Linux, in your particular case, you could be interested in using readline(3) instead of getline(3).
Don't forget to read the documentation of every function that you are using (e.g. here, if it is a standard C one).
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
add a comment |
You forgot to initialize buffer
. And you'll better end your printf(3) format control string with n
or else call fflush(3) before any input (since stdio(3) is buffered).
An uninitialized pointer contains garbage. Using it is undefined behavior. Be scared !
So my suggestion is to code
size_t bufsiz = 64;
char *buffer = malloc(bufsiz);
if (!buffer) { perror("malloc buffer"); exit(EXIT_FAILURE); };
and later
printf("Salut ! Quel est ton nom ?n");
characters = getline(&buffer,&bufsize,stdin);
Next time enable all warnings and debug info when compiling, so compile your code with gcc -Wall -Wextra -g
if using GCC. You would have got some warnings.
Of course, read How to debug small programs and debugging with GDB
On Linux, in your particular case, you could be interested in using readline(3) instead of getline(3).
Don't forget to read the documentation of every function that you are using (e.g. here, if it is a standard C one).
You forgot to initialize buffer
. And you'll better end your printf(3) format control string with n
or else call fflush(3) before any input (since stdio(3) is buffered).
An uninitialized pointer contains garbage. Using it is undefined behavior. Be scared !
So my suggestion is to code
size_t bufsiz = 64;
char *buffer = malloc(bufsiz);
if (!buffer) { perror("malloc buffer"); exit(EXIT_FAILURE); };
and later
printf("Salut ! Quel est ton nom ?n");
characters = getline(&buffer,&bufsize,stdin);
Next time enable all warnings and debug info when compiling, so compile your code with gcc -Wall -Wextra -g
if using GCC. You would have got some warnings.
Of course, read How to debug small programs and debugging with GDB
On Linux, in your particular case, you could be interested in using readline(3) instead of getline(3).
Don't forget to read the documentation of every function that you are using (e.g. here, if it is a standard C one).
edited Jan 19 at 11:32
answered Jan 19 at 11:10
Basile StarynkevitchBasile Starynkevitch
178k13169364
178k13169364
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
add a comment |
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Thank you It worked! but if my buffer wasn't poiting any memory , why does it did work with all my program and never had this error ?
– Chetrit
Jan 19 at 11:19
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Follow all the links I am giving in my answer
– Basile Starynkevitch
Jan 19 at 11:21
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
Thank you very much ! Have a great day !
– Chetrit
Jan 19 at 11:29
add a comment |
getline()
can be used in two different ways:
- Read into a buffer provided by the caller.
- Allocate memory when reading.
To use 1. initialise the pointer passed to point to valid memory and pass as well the size of the latter.
#define INITIAL_SIZE (42)
int main(void)
{
char * buffer = malloc(INITIAL_SIZE * sizeof *buffer);
size_t bufsize = INITIAL_SIZE;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
To use 2. initialise the pointer passed to NULL
and pass 0
as size.
int main(void)
{
char * buffer = NULL;
size_t bufsize = 0;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
Note: getline()
returns ssize_t
not size_t
.
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
add a comment |
getline()
can be used in two different ways:
- Read into a buffer provided by the caller.
- Allocate memory when reading.
To use 1. initialise the pointer passed to point to valid memory and pass as well the size of the latter.
#define INITIAL_SIZE (42)
int main(void)
{
char * buffer = malloc(INITIAL_SIZE * sizeof *buffer);
size_t bufsize = INITIAL_SIZE;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
To use 2. initialise the pointer passed to NULL
and pass 0
as size.
int main(void)
{
char * buffer = NULL;
size_t bufsize = 0;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
Note: getline()
returns ssize_t
not size_t
.
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
add a comment |
getline()
can be used in two different ways:
- Read into a buffer provided by the caller.
- Allocate memory when reading.
To use 1. initialise the pointer passed to point to valid memory and pass as well the size of the latter.
#define INITIAL_SIZE (42)
int main(void)
{
char * buffer = malloc(INITIAL_SIZE * sizeof *buffer);
size_t bufsize = INITIAL_SIZE;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
To use 2. initialise the pointer passed to NULL
and pass 0
as size.
int main(void)
{
char * buffer = NULL;
size_t bufsize = 0;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
Note: getline()
returns ssize_t
not size_t
.
getline()
can be used in two different ways:
- Read into a buffer provided by the caller.
- Allocate memory when reading.
To use 1. initialise the pointer passed to point to valid memory and pass as well the size of the latter.
#define INITIAL_SIZE (42)
int main(void)
{
char * buffer = malloc(INITIAL_SIZE * sizeof *buffer);
size_t bufsize = INITIAL_SIZE;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
To use 2. initialise the pointer passed to NULL
and pass 0
as size.
int main(void)
{
char * buffer = NULL;
size_t bufsize = 0;
ssize_t characters = getline(&buffer, &bufsize, stdin);
if (-1 == characters)
{
/* handle error. */
}
else
{
/* use buffer */
}
free(buffer); /* Free buffer. */
}
Note: getline()
returns ssize_t
not size_t
.
edited Jan 19 at 13:35
answered Jan 19 at 11:14
alkalk
58.6k763172
58.6k763172
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
add a comment |
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
Outsh! @NominalAnimal Fixed! Thx! :}
– alk
Jan 19 at 13:32
add a comment |
'buffer' variable is pointing to some garbage memory address. You need to allocate necessary memory first, using 'malloc' function or make 'buffer' a static array, instead of pointer.
1
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to usegetline()
.
– alk
Jan 19 at 11:21
add a comment |
'buffer' variable is pointing to some garbage memory address. You need to allocate necessary memory first, using 'malloc' function or make 'buffer' a static array, instead of pointer.
1
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to usegetline()
.
– alk
Jan 19 at 11:21
add a comment |
'buffer' variable is pointing to some garbage memory address. You need to allocate necessary memory first, using 'malloc' function or make 'buffer' a static array, instead of pointer.
'buffer' variable is pointing to some garbage memory address. You need to allocate necessary memory first, using 'malloc' function or make 'buffer' a static array, instead of pointer.
answered Jan 19 at 11:11
Starl1ghtStarl1ght
3,35111140
3,35111140
1
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to usegetline()
.
– alk
Jan 19 at 11:21
add a comment |
1
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to usegetline()
.
– alk
Jan 19 at 11:21
1
1
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to use
getline()
.– alk
Jan 19 at 11:21
"You need to allocate [...] memory first" not necessarily. Please see my answer of an alternative to use
getline()
.– alk
Jan 19 at 11:21
add a comment |
getline()
is a POSIX.1 function, which reads lines into dynamically allocated buffers, allowing lines of any length (limited only by the amount of available memory). It returns the number of characters read, or -1 if there is no more input, or an error occurred.
Here is one example use pattern:
char *line = NULL;
size_t size = 0;
ssize_t len;
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Do something with the input line */
}
At any point, you can release the dynamically allocated buffer using
free(line);
line = NULL;
size = 0;
The reason you want to clear the pointer to NULL and size to zero is that that way, you do not accidentally try to access the already freed memory, but you can call getline(&line, &size, handle)
to read more lines as the call will simply recognize it does not have a buffer, and will allocate a new one.
You can manipulate the dynamic data in any way you wish, if you are careful. For example:
while (1) {
char *line = NULL;
size_t size = 0;
ssize_t len;
len = getline(&line, &size, stdin);
if (len < 1) {
free(line);
break;
}
/* Do something with the contents of the line */
free(line);
}
will work, but it will be quite slow, because the C library will do at least one malloc()
call for every line read, and possibly additional realloc()
calls, depending on the line length.
The reason getline()
is written as it is, is that it allows reusing the same buffer for any number of lines. If you read files sequentially, you can reuse the same buffer. Let's look at a more complex example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
int main(int argc, char *argv)
{
unsigned long linenum;
char *line = NULL, *in, *out, *end;
size_t size = 0, n;
ssize_t len;
FILE *src;
int arg;
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.n");
if (argc < 2) {
fprintf(stderr, "n");
fprintf(stderr, "Usage: %s FILENAME [ FILENAME ... ]n", argv[0]);
fprintf(stderr, "n");
exit(EXIT_FAILURE);
}
for (arg = 1; arg < argc; arg++) {
src = fopen(argv[arg], "r");
if (!src) {
fprintf(stderr, "%s: %s.n", argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
linenum = 0;
while (1) {
len = getline(&line, &size, src);
if (len < 1)
break;
linenum++;
/* First character in the line read: */
in = line;
out = line;
/* Pointer to the end-of-string character on the line: */
end = line + len;
/* Skip all leading whitespace characters. */
while (in < end && isspace((unsigned char)(*in)))
in++;
/* Character copy loop. */
while (in < end)
if (isspace((unsigned char)(*in))) {
/* Replace consecutive whitespace characters with spaces. */
*(out++) = ' ';
do {
in++;
} while (in < end && isspace((unsigned char)(*in)));
} else {
/* Copy all other characters as-is. */
*(out++) = *(in++);
}
/* There may be a single space before out. Backtrack it, if so. */
if (out > line && out[-1] == ' ')
out--;
/* Mark the end of the string at out. */
*out = '';
/* Calculate the new length, just for output purposes. */
n = (size_t)(out - line);
/* Print the line. */
printf("%s: Line %lu: '%s' (%zu of %zd characters)n",
argv[arg], linenum, line, n, len);
}
if (!feof(src) || ferror(src)) {
fprintf(stderr, "%s: Read error.n", argv[arg]);
fclose(src);
free(line);
exit(EXIT_FAILURE);
}
if (fclose(src)) {
fprintf(stderr, "%s: Error closing file: %s.n",
argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
}
free(line);
line = NULL;
size = 0;
return EXIT_SUCCESS;
}
If we save the above as say example.c, and compile it using e.g. gcc -Wall -O2 example.c -o example
, and run the program supplying it with the names of text files as parameters, for example ./example example.c
, it will output something like
example.c: Line 1: '#define _POSIX_C_SOURCE 200809L' (31 of 33 characters)
example.c: Line 2: '#include <stdlib.h>' (19 of 20 characters)
example.c: Line 3: '#include <locale.h>' (19 of 20 characters)
example.c: Line 4: '#include <string.h>' (19 of 20 characters)
example.c: Line 5: '#include <stdio.h>' (18 of 19 characters)
example.c: Line 6: '#include <ctype.h>' (18 of 19 characters)
example.c: Line 7: '#include <errno.h>' (18 of 19 characters)
example.c: Line 8: '' (0 of 1 characters)
example.c: Line 9: 'int main(int argc, char *argv)' (32 of 33 characters)
What the program does, is simply read each specified file line by line, remove any leading and trailing whitespace on each line, and combine all consecutive whitespace into a single space. The smaller character count is the number of characters left (and shown), the larger number is the original number of chars read from the file.
Additional notes on the example program, if it happens to interest you
The
setlocale(LC_ALL, "")
call tells your C library to use the users locale (usually defined in theLANG
orLC_ALL
environment variables). This program uses only the character type definitions for the character set used by the current locale (to determine which codes are "whitespace"), so this could also be limited to that, viasetlocale(LC_CTYPE, "")
. The call will return NULL if the current locale is not supported by the C library. Usually that is because of an error in the user configuration, so it is useful to have the program warn then.The
isspace()
(and all otheris*()
functions defined in<ctype.h>
) take an unsigned character code (or EOF). Becausechar
type can be signed or unsigned, we explicitly cast the character to(unsigned char)
before supplying to the function. Consider this silly historical baggage that we just have to deal with this way.Because
line
points to the beginning of the dynamically allocated memory buffer, we must not modify it (except viarealloc()
, orfree()
and then set toNULL
). If we do modify it, any subsequentgetline()
orfree()
call using that pointer will likely freak out, and crash the program, since they really need the pointer to point to the beginning of the buffer, not just somewhere inside it.
I like using pointers (
char *in, *out, *end
) instead of indexes. Here,in
starts atline
, and goes up to but not includingline+len
, which is wheregetline()
put the end-of-string nulto indicate the end of the line. That's why I also often use a pointer named
end
to point to that. Theout
starts atline
also, but only increases when characters are kept in a line.
If you think about a row of lettered tiles, like in scrabble,
out
points to the next position you'll put a kept tile, andin
points to the next tile you get.
When
getline()
orgetdelim()
returns a zero or a negative value (orfgets()
returns NULL), it means that either there was no more data to read, or the operation failed for some other reason.
After the loop,
(!feof(src) || ferror(src))
checks if the input stream was read completely without errors. Well, rather, the inverse: the expression is true only if an error occurred, or the entire file was not read.
If I had written data to some file, say
FILE *dst
, I typically precede this test withif (fflush(dst))
test. It is true if there is an error writing the last of the data buffered by the C library to the file.
The
fclose(src)
closes the file. I personally prefer to verify its return value, because even though currently it can only fail in very specific circumstances, I as an user would definitely prefer to know if the OS had issues writing my data! The test costs basically nothing, but may be crucial for the user. I do not want any programs to "forget" telling me there was a problem, when working on my data; my data is important to me.
free(NULL)
is safe, and does nothing. (Also,realloc(NULL, size)
is equivalent tomalloc(size)
, so if you initialize a pointer to NULL, you don't need an initial malloc, you can justrealloc()
it always to the size you need.)
I suggest you play with the above code. You can even run it under ltrace (ltrace ./example example.c
) to see which standard C library calls are actually performed, and their results; or under strace (strace ./example example.c
) to see the syscalls (from the process to the OS kernel proper).
As an example, you could add say
if (linenum == 7) {
/* We skip line 7, and even destroy it! Muahhahah! */
free(line);
line = NULL;
size = 0;
continue;
}
just after the linenum++
line, to see what happens to the seventh lines of the text files. (They're skipped, and even if the buffer is released, nothing bad happens (because continue
starts the next iteration of the while loop body), as the next getline()
will just dynamically allocate a new line.
If you decide you want to keep a copy of part of the line, just calculate the length you need adding one for the end-of-string nul (), allocate that many chars for the duplicate (
sizeof (char) == 1
in C, always; so malloc() et al. take the number of chars to allocate for, really), memcpy()
the data, and add the terminating nul. For example,
char *sdup(const char *const source, const size_t length)
{
char *s;
s = malloc(length + 1);
if (!s) {
/* Either return NULL, or: */
fprintf(stderr, "sdup(): Not enough memory for %zu chars.n", length + 1);
exit(EXIT_FAILURE);
}
if (length > 0)
memcpy(s, source, length);
s[length] = '';
return s;
}
If you want the full string (up to end of string nul), you can use the POSIX.1-2008 strdup()
instead.
add a comment |
getline()
is a POSIX.1 function, which reads lines into dynamically allocated buffers, allowing lines of any length (limited only by the amount of available memory). It returns the number of characters read, or -1 if there is no more input, or an error occurred.
Here is one example use pattern:
char *line = NULL;
size_t size = 0;
ssize_t len;
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Do something with the input line */
}
At any point, you can release the dynamically allocated buffer using
free(line);
line = NULL;
size = 0;
The reason you want to clear the pointer to NULL and size to zero is that that way, you do not accidentally try to access the already freed memory, but you can call getline(&line, &size, handle)
to read more lines as the call will simply recognize it does not have a buffer, and will allocate a new one.
You can manipulate the dynamic data in any way you wish, if you are careful. For example:
while (1) {
char *line = NULL;
size_t size = 0;
ssize_t len;
len = getline(&line, &size, stdin);
if (len < 1) {
free(line);
break;
}
/* Do something with the contents of the line */
free(line);
}
will work, but it will be quite slow, because the C library will do at least one malloc()
call for every line read, and possibly additional realloc()
calls, depending on the line length.
The reason getline()
is written as it is, is that it allows reusing the same buffer for any number of lines. If you read files sequentially, you can reuse the same buffer. Let's look at a more complex example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
int main(int argc, char *argv)
{
unsigned long linenum;
char *line = NULL, *in, *out, *end;
size_t size = 0, n;
ssize_t len;
FILE *src;
int arg;
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.n");
if (argc < 2) {
fprintf(stderr, "n");
fprintf(stderr, "Usage: %s FILENAME [ FILENAME ... ]n", argv[0]);
fprintf(stderr, "n");
exit(EXIT_FAILURE);
}
for (arg = 1; arg < argc; arg++) {
src = fopen(argv[arg], "r");
if (!src) {
fprintf(stderr, "%s: %s.n", argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
linenum = 0;
while (1) {
len = getline(&line, &size, src);
if (len < 1)
break;
linenum++;
/* First character in the line read: */
in = line;
out = line;
/* Pointer to the end-of-string character on the line: */
end = line + len;
/* Skip all leading whitespace characters. */
while (in < end && isspace((unsigned char)(*in)))
in++;
/* Character copy loop. */
while (in < end)
if (isspace((unsigned char)(*in))) {
/* Replace consecutive whitespace characters with spaces. */
*(out++) = ' ';
do {
in++;
} while (in < end && isspace((unsigned char)(*in)));
} else {
/* Copy all other characters as-is. */
*(out++) = *(in++);
}
/* There may be a single space before out. Backtrack it, if so. */
if (out > line && out[-1] == ' ')
out--;
/* Mark the end of the string at out. */
*out = '';
/* Calculate the new length, just for output purposes. */
n = (size_t)(out - line);
/* Print the line. */
printf("%s: Line %lu: '%s' (%zu of %zd characters)n",
argv[arg], linenum, line, n, len);
}
if (!feof(src) || ferror(src)) {
fprintf(stderr, "%s: Read error.n", argv[arg]);
fclose(src);
free(line);
exit(EXIT_FAILURE);
}
if (fclose(src)) {
fprintf(stderr, "%s: Error closing file: %s.n",
argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
}
free(line);
line = NULL;
size = 0;
return EXIT_SUCCESS;
}
If we save the above as say example.c, and compile it using e.g. gcc -Wall -O2 example.c -o example
, and run the program supplying it with the names of text files as parameters, for example ./example example.c
, it will output something like
example.c: Line 1: '#define _POSIX_C_SOURCE 200809L' (31 of 33 characters)
example.c: Line 2: '#include <stdlib.h>' (19 of 20 characters)
example.c: Line 3: '#include <locale.h>' (19 of 20 characters)
example.c: Line 4: '#include <string.h>' (19 of 20 characters)
example.c: Line 5: '#include <stdio.h>' (18 of 19 characters)
example.c: Line 6: '#include <ctype.h>' (18 of 19 characters)
example.c: Line 7: '#include <errno.h>' (18 of 19 characters)
example.c: Line 8: '' (0 of 1 characters)
example.c: Line 9: 'int main(int argc, char *argv)' (32 of 33 characters)
What the program does, is simply read each specified file line by line, remove any leading and trailing whitespace on each line, and combine all consecutive whitespace into a single space. The smaller character count is the number of characters left (and shown), the larger number is the original number of chars read from the file.
Additional notes on the example program, if it happens to interest you
The
setlocale(LC_ALL, "")
call tells your C library to use the users locale (usually defined in theLANG
orLC_ALL
environment variables). This program uses only the character type definitions for the character set used by the current locale (to determine which codes are "whitespace"), so this could also be limited to that, viasetlocale(LC_CTYPE, "")
. The call will return NULL if the current locale is not supported by the C library. Usually that is because of an error in the user configuration, so it is useful to have the program warn then.The
isspace()
(and all otheris*()
functions defined in<ctype.h>
) take an unsigned character code (or EOF). Becausechar
type can be signed or unsigned, we explicitly cast the character to(unsigned char)
before supplying to the function. Consider this silly historical baggage that we just have to deal with this way.Because
line
points to the beginning of the dynamically allocated memory buffer, we must not modify it (except viarealloc()
, orfree()
and then set toNULL
). If we do modify it, any subsequentgetline()
orfree()
call using that pointer will likely freak out, and crash the program, since they really need the pointer to point to the beginning of the buffer, not just somewhere inside it.
I like using pointers (
char *in, *out, *end
) instead of indexes. Here,in
starts atline
, and goes up to but not includingline+len
, which is wheregetline()
put the end-of-string nulto indicate the end of the line. That's why I also often use a pointer named
end
to point to that. Theout
starts atline
also, but only increases when characters are kept in a line.
If you think about a row of lettered tiles, like in scrabble,
out
points to the next position you'll put a kept tile, andin
points to the next tile you get.
When
getline()
orgetdelim()
returns a zero or a negative value (orfgets()
returns NULL), it means that either there was no more data to read, or the operation failed for some other reason.
After the loop,
(!feof(src) || ferror(src))
checks if the input stream was read completely without errors. Well, rather, the inverse: the expression is true only if an error occurred, or the entire file was not read.
If I had written data to some file, say
FILE *dst
, I typically precede this test withif (fflush(dst))
test. It is true if there is an error writing the last of the data buffered by the C library to the file.
The
fclose(src)
closes the file. I personally prefer to verify its return value, because even though currently it can only fail in very specific circumstances, I as an user would definitely prefer to know if the OS had issues writing my data! The test costs basically nothing, but may be crucial for the user. I do not want any programs to "forget" telling me there was a problem, when working on my data; my data is important to me.
free(NULL)
is safe, and does nothing. (Also,realloc(NULL, size)
is equivalent tomalloc(size)
, so if you initialize a pointer to NULL, you don't need an initial malloc, you can justrealloc()
it always to the size you need.)
I suggest you play with the above code. You can even run it under ltrace (ltrace ./example example.c
) to see which standard C library calls are actually performed, and their results; or under strace (strace ./example example.c
) to see the syscalls (from the process to the OS kernel proper).
As an example, you could add say
if (linenum == 7) {
/* We skip line 7, and even destroy it! Muahhahah! */
free(line);
line = NULL;
size = 0;
continue;
}
just after the linenum++
line, to see what happens to the seventh lines of the text files. (They're skipped, and even if the buffer is released, nothing bad happens (because continue
starts the next iteration of the while loop body), as the next getline()
will just dynamically allocate a new line.
If you decide you want to keep a copy of part of the line, just calculate the length you need adding one for the end-of-string nul (), allocate that many chars for the duplicate (
sizeof (char) == 1
in C, always; so malloc() et al. take the number of chars to allocate for, really), memcpy()
the data, and add the terminating nul. For example,
char *sdup(const char *const source, const size_t length)
{
char *s;
s = malloc(length + 1);
if (!s) {
/* Either return NULL, or: */
fprintf(stderr, "sdup(): Not enough memory for %zu chars.n", length + 1);
exit(EXIT_FAILURE);
}
if (length > 0)
memcpy(s, source, length);
s[length] = '';
return s;
}
If you want the full string (up to end of string nul), you can use the POSIX.1-2008 strdup()
instead.
add a comment |
getline()
is a POSIX.1 function, which reads lines into dynamically allocated buffers, allowing lines of any length (limited only by the amount of available memory). It returns the number of characters read, or -1 if there is no more input, or an error occurred.
Here is one example use pattern:
char *line = NULL;
size_t size = 0;
ssize_t len;
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Do something with the input line */
}
At any point, you can release the dynamically allocated buffer using
free(line);
line = NULL;
size = 0;
The reason you want to clear the pointer to NULL and size to zero is that that way, you do not accidentally try to access the already freed memory, but you can call getline(&line, &size, handle)
to read more lines as the call will simply recognize it does not have a buffer, and will allocate a new one.
You can manipulate the dynamic data in any way you wish, if you are careful. For example:
while (1) {
char *line = NULL;
size_t size = 0;
ssize_t len;
len = getline(&line, &size, stdin);
if (len < 1) {
free(line);
break;
}
/* Do something with the contents of the line */
free(line);
}
will work, but it will be quite slow, because the C library will do at least one malloc()
call for every line read, and possibly additional realloc()
calls, depending on the line length.
The reason getline()
is written as it is, is that it allows reusing the same buffer for any number of lines. If you read files sequentially, you can reuse the same buffer. Let's look at a more complex example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
int main(int argc, char *argv)
{
unsigned long linenum;
char *line = NULL, *in, *out, *end;
size_t size = 0, n;
ssize_t len;
FILE *src;
int arg;
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.n");
if (argc < 2) {
fprintf(stderr, "n");
fprintf(stderr, "Usage: %s FILENAME [ FILENAME ... ]n", argv[0]);
fprintf(stderr, "n");
exit(EXIT_FAILURE);
}
for (arg = 1; arg < argc; arg++) {
src = fopen(argv[arg], "r");
if (!src) {
fprintf(stderr, "%s: %s.n", argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
linenum = 0;
while (1) {
len = getline(&line, &size, src);
if (len < 1)
break;
linenum++;
/* First character in the line read: */
in = line;
out = line;
/* Pointer to the end-of-string character on the line: */
end = line + len;
/* Skip all leading whitespace characters. */
while (in < end && isspace((unsigned char)(*in)))
in++;
/* Character copy loop. */
while (in < end)
if (isspace((unsigned char)(*in))) {
/* Replace consecutive whitespace characters with spaces. */
*(out++) = ' ';
do {
in++;
} while (in < end && isspace((unsigned char)(*in)));
} else {
/* Copy all other characters as-is. */
*(out++) = *(in++);
}
/* There may be a single space before out. Backtrack it, if so. */
if (out > line && out[-1] == ' ')
out--;
/* Mark the end of the string at out. */
*out = '';
/* Calculate the new length, just for output purposes. */
n = (size_t)(out - line);
/* Print the line. */
printf("%s: Line %lu: '%s' (%zu of %zd characters)n",
argv[arg], linenum, line, n, len);
}
if (!feof(src) || ferror(src)) {
fprintf(stderr, "%s: Read error.n", argv[arg]);
fclose(src);
free(line);
exit(EXIT_FAILURE);
}
if (fclose(src)) {
fprintf(stderr, "%s: Error closing file: %s.n",
argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
}
free(line);
line = NULL;
size = 0;
return EXIT_SUCCESS;
}
If we save the above as say example.c, and compile it using e.g. gcc -Wall -O2 example.c -o example
, and run the program supplying it with the names of text files as parameters, for example ./example example.c
, it will output something like
example.c: Line 1: '#define _POSIX_C_SOURCE 200809L' (31 of 33 characters)
example.c: Line 2: '#include <stdlib.h>' (19 of 20 characters)
example.c: Line 3: '#include <locale.h>' (19 of 20 characters)
example.c: Line 4: '#include <string.h>' (19 of 20 characters)
example.c: Line 5: '#include <stdio.h>' (18 of 19 characters)
example.c: Line 6: '#include <ctype.h>' (18 of 19 characters)
example.c: Line 7: '#include <errno.h>' (18 of 19 characters)
example.c: Line 8: '' (0 of 1 characters)
example.c: Line 9: 'int main(int argc, char *argv)' (32 of 33 characters)
What the program does, is simply read each specified file line by line, remove any leading and trailing whitespace on each line, and combine all consecutive whitespace into a single space. The smaller character count is the number of characters left (and shown), the larger number is the original number of chars read from the file.
Additional notes on the example program, if it happens to interest you
The
setlocale(LC_ALL, "")
call tells your C library to use the users locale (usually defined in theLANG
orLC_ALL
environment variables). This program uses only the character type definitions for the character set used by the current locale (to determine which codes are "whitespace"), so this could also be limited to that, viasetlocale(LC_CTYPE, "")
. The call will return NULL if the current locale is not supported by the C library. Usually that is because of an error in the user configuration, so it is useful to have the program warn then.The
isspace()
(and all otheris*()
functions defined in<ctype.h>
) take an unsigned character code (or EOF). Becausechar
type can be signed or unsigned, we explicitly cast the character to(unsigned char)
before supplying to the function. Consider this silly historical baggage that we just have to deal with this way.Because
line
points to the beginning of the dynamically allocated memory buffer, we must not modify it (except viarealloc()
, orfree()
and then set toNULL
). If we do modify it, any subsequentgetline()
orfree()
call using that pointer will likely freak out, and crash the program, since they really need the pointer to point to the beginning of the buffer, not just somewhere inside it.
I like using pointers (
char *in, *out, *end
) instead of indexes. Here,in
starts atline
, and goes up to but not includingline+len
, which is wheregetline()
put the end-of-string nulto indicate the end of the line. That's why I also often use a pointer named
end
to point to that. Theout
starts atline
also, but only increases when characters are kept in a line.
If you think about a row of lettered tiles, like in scrabble,
out
points to the next position you'll put a kept tile, andin
points to the next tile you get.
When
getline()
orgetdelim()
returns a zero or a negative value (orfgets()
returns NULL), it means that either there was no more data to read, or the operation failed for some other reason.
After the loop,
(!feof(src) || ferror(src))
checks if the input stream was read completely without errors. Well, rather, the inverse: the expression is true only if an error occurred, or the entire file was not read.
If I had written data to some file, say
FILE *dst
, I typically precede this test withif (fflush(dst))
test. It is true if there is an error writing the last of the data buffered by the C library to the file.
The
fclose(src)
closes the file. I personally prefer to verify its return value, because even though currently it can only fail in very specific circumstances, I as an user would definitely prefer to know if the OS had issues writing my data! The test costs basically nothing, but may be crucial for the user. I do not want any programs to "forget" telling me there was a problem, when working on my data; my data is important to me.
free(NULL)
is safe, and does nothing. (Also,realloc(NULL, size)
is equivalent tomalloc(size)
, so if you initialize a pointer to NULL, you don't need an initial malloc, you can justrealloc()
it always to the size you need.)
I suggest you play with the above code. You can even run it under ltrace (ltrace ./example example.c
) to see which standard C library calls are actually performed, and their results; or under strace (strace ./example example.c
) to see the syscalls (from the process to the OS kernel proper).
As an example, you could add say
if (linenum == 7) {
/* We skip line 7, and even destroy it! Muahhahah! */
free(line);
line = NULL;
size = 0;
continue;
}
just after the linenum++
line, to see what happens to the seventh lines of the text files. (They're skipped, and even if the buffer is released, nothing bad happens (because continue
starts the next iteration of the while loop body), as the next getline()
will just dynamically allocate a new line.
If you decide you want to keep a copy of part of the line, just calculate the length you need adding one for the end-of-string nul (), allocate that many chars for the duplicate (
sizeof (char) == 1
in C, always; so malloc() et al. take the number of chars to allocate for, really), memcpy()
the data, and add the terminating nul. For example,
char *sdup(const char *const source, const size_t length)
{
char *s;
s = malloc(length + 1);
if (!s) {
/* Either return NULL, or: */
fprintf(stderr, "sdup(): Not enough memory for %zu chars.n", length + 1);
exit(EXIT_FAILURE);
}
if (length > 0)
memcpy(s, source, length);
s[length] = '';
return s;
}
If you want the full string (up to end of string nul), you can use the POSIX.1-2008 strdup()
instead.
getline()
is a POSIX.1 function, which reads lines into dynamically allocated buffers, allowing lines of any length (limited only by the amount of available memory). It returns the number of characters read, or -1 if there is no more input, or an error occurred.
Here is one example use pattern:
char *line = NULL;
size_t size = 0;
ssize_t len;
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Do something with the input line */
}
At any point, you can release the dynamically allocated buffer using
free(line);
line = NULL;
size = 0;
The reason you want to clear the pointer to NULL and size to zero is that that way, you do not accidentally try to access the already freed memory, but you can call getline(&line, &size, handle)
to read more lines as the call will simply recognize it does not have a buffer, and will allocate a new one.
You can manipulate the dynamic data in any way you wish, if you are careful. For example:
while (1) {
char *line = NULL;
size_t size = 0;
ssize_t len;
len = getline(&line, &size, stdin);
if (len < 1) {
free(line);
break;
}
/* Do something with the contents of the line */
free(line);
}
will work, but it will be quite slow, because the C library will do at least one malloc()
call for every line read, and possibly additional realloc()
calls, depending on the line length.
The reason getline()
is written as it is, is that it allows reusing the same buffer for any number of lines. If you read files sequentially, you can reuse the same buffer. Let's look at a more complex example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
int main(int argc, char *argv)
{
unsigned long linenum;
char *line = NULL, *in, *out, *end;
size_t size = 0, n;
ssize_t len;
FILE *src;
int arg;
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.n");
if (argc < 2) {
fprintf(stderr, "n");
fprintf(stderr, "Usage: %s FILENAME [ FILENAME ... ]n", argv[0]);
fprintf(stderr, "n");
exit(EXIT_FAILURE);
}
for (arg = 1; arg < argc; arg++) {
src = fopen(argv[arg], "r");
if (!src) {
fprintf(stderr, "%s: %s.n", argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
linenum = 0;
while (1) {
len = getline(&line, &size, src);
if (len < 1)
break;
linenum++;
/* First character in the line read: */
in = line;
out = line;
/* Pointer to the end-of-string character on the line: */
end = line + len;
/* Skip all leading whitespace characters. */
while (in < end && isspace((unsigned char)(*in)))
in++;
/* Character copy loop. */
while (in < end)
if (isspace((unsigned char)(*in))) {
/* Replace consecutive whitespace characters with spaces. */
*(out++) = ' ';
do {
in++;
} while (in < end && isspace((unsigned char)(*in)));
} else {
/* Copy all other characters as-is. */
*(out++) = *(in++);
}
/* There may be a single space before out. Backtrack it, if so. */
if (out > line && out[-1] == ' ')
out--;
/* Mark the end of the string at out. */
*out = '';
/* Calculate the new length, just for output purposes. */
n = (size_t)(out - line);
/* Print the line. */
printf("%s: Line %lu: '%s' (%zu of %zd characters)n",
argv[arg], linenum, line, n, len);
}
if (!feof(src) || ferror(src)) {
fprintf(stderr, "%s: Read error.n", argv[arg]);
fclose(src);
free(line);
exit(EXIT_FAILURE);
}
if (fclose(src)) {
fprintf(stderr, "%s: Error closing file: %s.n",
argv[arg], strerror(errno));
free(line);
exit(EXIT_FAILURE);
}
}
free(line);
line = NULL;
size = 0;
return EXIT_SUCCESS;
}
If we save the above as say example.c, and compile it using e.g. gcc -Wall -O2 example.c -o example
, and run the program supplying it with the names of text files as parameters, for example ./example example.c
, it will output something like
example.c: Line 1: '#define _POSIX_C_SOURCE 200809L' (31 of 33 characters)
example.c: Line 2: '#include <stdlib.h>' (19 of 20 characters)
example.c: Line 3: '#include <locale.h>' (19 of 20 characters)
example.c: Line 4: '#include <string.h>' (19 of 20 characters)
example.c: Line 5: '#include <stdio.h>' (18 of 19 characters)
example.c: Line 6: '#include <ctype.h>' (18 of 19 characters)
example.c: Line 7: '#include <errno.h>' (18 of 19 characters)
example.c: Line 8: '' (0 of 1 characters)
example.c: Line 9: 'int main(int argc, char *argv)' (32 of 33 characters)
What the program does, is simply read each specified file line by line, remove any leading and trailing whitespace on each line, and combine all consecutive whitespace into a single space. The smaller character count is the number of characters left (and shown), the larger number is the original number of chars read from the file.
Additional notes on the example program, if it happens to interest you
The
setlocale(LC_ALL, "")
call tells your C library to use the users locale (usually defined in theLANG
orLC_ALL
environment variables). This program uses only the character type definitions for the character set used by the current locale (to determine which codes are "whitespace"), so this could also be limited to that, viasetlocale(LC_CTYPE, "")
. The call will return NULL if the current locale is not supported by the C library. Usually that is because of an error in the user configuration, so it is useful to have the program warn then.The
isspace()
(and all otheris*()
functions defined in<ctype.h>
) take an unsigned character code (or EOF). Becausechar
type can be signed or unsigned, we explicitly cast the character to(unsigned char)
before supplying to the function. Consider this silly historical baggage that we just have to deal with this way.Because
line
points to the beginning of the dynamically allocated memory buffer, we must not modify it (except viarealloc()
, orfree()
and then set toNULL
). If we do modify it, any subsequentgetline()
orfree()
call using that pointer will likely freak out, and crash the program, since they really need the pointer to point to the beginning of the buffer, not just somewhere inside it.
I like using pointers (
char *in, *out, *end
) instead of indexes. Here,in
starts atline
, and goes up to but not includingline+len
, which is wheregetline()
put the end-of-string nulto indicate the end of the line. That's why I also often use a pointer named
end
to point to that. Theout
starts atline
also, but only increases when characters are kept in a line.
If you think about a row of lettered tiles, like in scrabble,
out
points to the next position you'll put a kept tile, andin
points to the next tile you get.
When
getline()
orgetdelim()
returns a zero or a negative value (orfgets()
returns NULL), it means that either there was no more data to read, or the operation failed for some other reason.
After the loop,
(!feof(src) || ferror(src))
checks if the input stream was read completely without errors. Well, rather, the inverse: the expression is true only if an error occurred, or the entire file was not read.
If I had written data to some file, say
FILE *dst
, I typically precede this test withif (fflush(dst))
test. It is true if there is an error writing the last of the data buffered by the C library to the file.
The
fclose(src)
closes the file. I personally prefer to verify its return value, because even though currently it can only fail in very specific circumstances, I as an user would definitely prefer to know if the OS had issues writing my data! The test costs basically nothing, but may be crucial for the user. I do not want any programs to "forget" telling me there was a problem, when working on my data; my data is important to me.
free(NULL)
is safe, and does nothing. (Also,realloc(NULL, size)
is equivalent tomalloc(size)
, so if you initialize a pointer to NULL, you don't need an initial malloc, you can justrealloc()
it always to the size you need.)
I suggest you play with the above code. You can even run it under ltrace (ltrace ./example example.c
) to see which standard C library calls are actually performed, and their results; or under strace (strace ./example example.c
) to see the syscalls (from the process to the OS kernel proper).
As an example, you could add say
if (linenum == 7) {
/* We skip line 7, and even destroy it! Muahhahah! */
free(line);
line = NULL;
size = 0;
continue;
}
just after the linenum++
line, to see what happens to the seventh lines of the text files. (They're skipped, and even if the buffer is released, nothing bad happens (because continue
starts the next iteration of the while loop body), as the next getline()
will just dynamically allocate a new line.
If you decide you want to keep a copy of part of the line, just calculate the length you need adding one for the end-of-string nul (), allocate that many chars for the duplicate (
sizeof (char) == 1
in C, always; so malloc() et al. take the number of chars to allocate for, really), memcpy()
the data, and add the terminating nul. For example,
char *sdup(const char *const source, const size_t length)
{
char *s;
s = malloc(length + 1);
if (!s) {
/* Either return NULL, or: */
fprintf(stderr, "sdup(): Not enough memory for %zu chars.n", length + 1);
exit(EXIT_FAILURE);
}
if (length > 0)
memcpy(s, source, length);
s[length] = '';
return s;
}
If you want the full string (up to end of string nul), you can use the POSIX.1-2008 strdup()
instead.
answered Jan 19 at 14:14
Nominal AnimalNominal Animal
30k33361
30k33361
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54266432%2fsegmentation-error-with-getline-function%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
None of your pointers are initialized to point at valid memory
– UnholySheep
Jan 19 at 11:10
2
@UnholySheep ... or
NULL
or0
.– alk
Jan 19 at 11:11