There are a number of ways to approach this problem. As others have correctly shown, if you know your input will not exceed a certain size, you can declare a static buffer
sufficient to hold your data. However, if you find yourself in the situation where you don't know how much data you need to read, then you can turn to dynamically allocating
your buffer which provides you the ability to grow (or realloc
) the size of your buffer as needed. The following provides that approach. (you can redirect a textfile to it as a test).
Also, it was unclear, if you wanted to skip all blank lines, or if you just didn't want to see input until EOF
. At any rate, if you wanted to skip blank lines you can add a simple test inside the read loop after you assign p = line;
.
/* skip blank lines */
if (*p == '\n' || *p == '\r')
continue;
This example uses getline
instead of fgets
which provides 2 advantages for you. (1) getline
will allocate the line-buffer for you if you initialize it to NULL
; and (2) it returns the actual number of characters read, eliminating the need to call strlen
. Let me know if you have questions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *realloc_void_on (void *p, size_t o, size_t n, size_t psz);
int main (void) {
char *line = NULL; /* pointer to use with getline () */
char *p = NULL; /* pointer to parse getline return */
ssize_t nchr = 0; /* actual chars read per-line */
size_t n = 0; /* max chars to read (0 - no limit) */
char *buff = NULL; /* buffer to hold all lines read */
char *ep = NULL; /* end pointer for buff */
size_t cbuffsz = 0; /* current buffer size */
size_t nbuffsz = 0; /* new buffer size */
size_t offset = 0; /* offset to orient end pointer */
/* read each line from stdin */
while ((nchr = getline (&line, &n, stdin)) != -1)
{
p = line; /* assign line address to pointer */
/* set required new buff size, realloc, set end ptr, update cbuffsz */
nbuffsz += nchr + 1;
buff = realloc_void_on (buff, cbuffsz, nbuffsz, sizeof *buff);
ep = buff + offset;
cbuffsz = nbuffsz;
while (*p) { /* for each character in line */
*ep++ = *p; /* add char to buff, increment ep */
offset++; /* increment offset */
if (*p == '\t' || *p == ' ') { /* if space, or tab */
while (*p == '\t' || *p == ' ') /* read/discard following spaces */
p++;
}
else
p++; /* if not space, increment pointer */
}
}
/* output complete buffer */
#ifdef DEBUG
printf ("\nBuffer:\n-----\n%s-----\n\n", buff);
#else
printf ("%s\n", buff);
#endif
/* free allocated memory */
if (line) free (line);
if (buff) free (buff);
return 0;
}
/* reallocate memory for p of type size psz, from o to n.
* accepts any pointer p, with current allocation o,
* with the type size psz and reallocates memory to
* n, intializing the new memory to zero and returning
* a pointer to the newly allocated block of memory on
* success, exit otherwise.
*/
void *realloc_void_on (void *p, size_t o, size_t n, size_t psz)
{
void *tmp = realloc (p, n * psz);
#ifdef DEBUG
printf ("\n reallocating %zu to %zu\n", o, n);
#endif
if (!tmp) {
fprintf (stderr, "Error: pointer reallocation failure.\n");
exit (EXIT_FAILURE);
}
p = tmp;
memset (p + o, 0, (n - o) * psz); /* memset new ptrs 0 */
return p;
}
Build/Compile
Without realloc DEBUG info:
gcc -Wall -Wextra -o buildbuf buildbuf.c
With realloc DEBUG info (including gdb
debug info):
gcc -Wall -Wextra -g -DDEBUG -o buildbuf buildbuf.c
Input
I am running.
Output
I am running.