Reputation: 41
I am trying to create a program that will read line by line from stdin, search that line for the start and end of a given word and output all the matching words. Here is the code:
int main()
{
char buffer[100];
char **words = NULL;
int word_count = 0;
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
int length = strlen(buffer);
if (buffer[length - 1] == '\n') {
word_count = count_words(buffer, FIRSTCHAR);
if (word_count > 0) {
words = get_words(buffer, FIRSTCHAR, LASTCHAR);
for (int i = 0; i < word_count; ++i) {
printf("%s\n", words[i]);
free(words[i]);
}
free(words);
}
}
}
return 0;
}
I got the basic functionality working, but I am relying on fgets() with a fixed buffer size. What I would like is to dynamically allocate a memory buffer with a size based on the length of each line.
I can only see one way of going about solving it, which is to iterate over input with fgetc and increment a counter until end of line and use that counter in place of sizeof(buffer), but I don't know how I would get fgetc to read the correct relevant line.
Is there any smart way of solving this?
Upvotes: 4
Views: 8349
Reputation: 16540
the function: getline()
does just what you want. The syntax:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
The function is exposed in the stdio.h
header file and usually requires something like: #define _POSIX_C_SOURCE 200809L
or #define _GNU_SOURCE
as the first line in the file that calls getline()
Strongly suggest reading/understanding the MAN page for `getline() for all the grubby details.
Upvotes: 0
Reputation: 13580
but I am relying on
fgets()
with a fixed buffer size. What I would like is to dynamically allocate a memory buffer with a size based on the length of each line
I did wrote a version of fgets
for another SO answer that reads the whole line and returns a
malloc
allocated pointer with the contents of the whole line. This is the
code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *fgets_long(FILE *fp)
{
size_t size = 0, currlen = 0;
char line[1024];
char *ret = NULL, *tmp;
while(fgets(line, sizeof line, fp))
{
int wholeline = 0;
size_t len = strlen(line);
if(line[len - 1] == '\n')
{
line[len-- - 1] = 0;
wholeline = 1;
}
if(currlen + len >= size)
{
// we need more space in the buffer
size += (sizeof line) - (size ? 1 : 0);
tmp = realloc(ret, size);
if(tmp == NULL)
break; // return all we've got so far
ret = tmp;
}
memcpy(ret + currlen, line, len + 1);
currlen += len;
if(wholeline)
break;
}
if(ret)
{
tmp = realloc(ret, currlen + 1);
if(tmp)
ret = tmp;
}
return ret;
}
The trick is to check if the newline was read. If it was read, then you can
return the buffer, otherwise it reallocates the buffer with sizeof line
more
bytes and appends it to the buffer. You could use this function if you like.
An alternative would be if you are using a POSIX system and/or are compiling with GNU GCC, then you
can use getline
as well.
void foo(FILE *fp)
{
char *line = NULL;
size_t len = 0;
if(getline(&line, &len, fp) < 0)
{
free(line); // man page says even on failure you should free
fprintf(stderr, "could not read whole line\n");
return;
}
printf("The whole line is: '%s'\n", line);
free(line);
return;
}
Upvotes: 5