ElSHEN ElSHEN - 1 year ago 199
C Question

Using fgetc() for reading into an array in C

I wanna use

and put the input character in some array like
char *ch
. But apparently I can't put character (like 'M') in array and it has to be like "M", I mean with double quotation like a string.

This is my code, after getting user input I got
Segmentation fault (core dumped)

So I want to know if there is any way or trick that could do that.

Thanks in advance. :)

void main(){
char *ch;
int i = 0;
while((ch[i] = fgetc(stdin)) != '\n'){

Answer Source

While you can realloc for every character you read, that is a horribly inefficient way to allocate memory. A call to malloc is relatively expensive compared to an assignment of a character to an array element. It is far better to allocate some reasonably anticipated number of characters, read until your reach the limit, realloc at that point (updating the limit), and repeat until EOF (or whatever termination you choose).

The implementation is straight forward, but there are a couple of subtleties to note. When reallocating, always assign the result of realloc to a temporary pointer so you can validate that realloc succeeded before proceeding. Why? If realloc fails, it returns NULL. If you just blindly assign the result to your original array, and realloc fails, (1) you have just lost the pointer to your original array; and (2) you have just created a memory leak because the original block is left untouched -- it is not freed or moved.

With that in mind, you could read characters into an array, reallocating as needed, until EOF is reaches using something like the following:

#include <stdio.h>
#include <stdlib.h>

#define NCHAR 1024  /* must be at least 1 */

int main (int argc, char **argv) {

    int c;
    size_t n = 0, nchar = NCHAR;
    char *arr = malloc (sizeof *arr * nchar);
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;

    if (!arr) { /* validate memory allocation succeeded */
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;

    while ((c = fgetc (fp)) != EOF) {  /* for each char in file */
        arr[n++] = c;       /* assign char to array */

        if (n == nchar) {   /* realloc preserving space for nul */
            void *tmp = realloc (arr, nchar + NCHAR);
            if (!tmp) {           /* validate realloc succeeded */
                fprintf (stderr, "realloc() error: memory exhausted.\n");
                break; /* break read loop, using existing 'arr' */
            arr = tmp;     /* assign reallocated pointer to arr */
            nchar += NCHAR;        /* update the value of nchar */
    arr[n] = 0;                  /* affirmatively nul-terminate */

    if (fp != stdin) fclose (fp);    /* close file if not stdin */

    for (size_t i = 0; i < n; i++)   /* output arr */
    putchar (arr[i]);

    free (arr);   /* free allocated memory */

    return 0;

(note: above, on failure, the read loop is exited, preserving all characters in arr read up to that point in time.)

Lastly, in any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated. (For Linux valgrind is the normal choice.)

A simple example (with NCHAR set to 2 to force multiple reallocations) would be:

$ valgrind ./bin/fgetc_realloc <../dat/captnjack.txt
==19710== Memcheck, a memory error detector
==19710== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==19710== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==19710== Command: ./bin/fgetc_realloc
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
==19710== HEAP SUMMARY:
==19710==     in use at exit: 0 bytes in 0 blocks
==19710==   total heap usage: 39 allocs, 39 frees, 1,560 bytes allocated
==19710== All heap blocks were freed -- no leaks are possible
==19710== For counts of detected and suppressed errors, rerun with: -v
==19710== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

You want to find All heap blocks were freed -- no leaks are possible and ERROR SUMMARY: 0 errors from 0 contexts (noting: on some OS, valgrind will not report 0 due to incomplete memory exclusion files)

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download