4

I wrote a code to read a file. Read the default file or another file and store the content file in a string. I don't know where I went wrong! When I run it, sometimes it's ok, but sometimes I get a Core Dump error!

This is my code:

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

#define BUFFER_SIZE 1024
#define EXAMPLE_FILE "programing_languages.example"
#define EXAMPLE_FILE_SIZE strlen(EXAMPLE_FILE)+1


int read_file(char *buffer, char *file_name)
{
    FILE *file;

    file = fopen(file_name, "r");

    if (file == NULL)
    {
        printf("Warning!!!");
        return 1;
    }

    fread(buffer, sizeof(char), BUFFER_SIZE, file);

    fclose(file);

    return 0;
}


int main(int argc, char *argv[])
{   
    int opt;
    int file_name_customized = 0;
    char *file_name;

    while ((opt = getopt(argc, argv, "f:")) != -1) {
        switch (opt) {
            case 'f':
                snprintf(file_name, strlen(argv[2])+1, "%s", argv[2]);
                file_name_customized = 1;
                break;
            default:
                snprintf(file_name, EXAMPLE_FILE_SIZE, EXAMPLE_FILE);
        }
    }

    if (!file_name_customized)
    {
        snprintf(file_name, EXAMPLE_FILE_SIZE, EXAMPLE_FILE);
    }

    char buffer[BUFFER_SIZE] = {"\0"};

    if (read_file(buffer, EXAMPLE_FILE) == 1)
    {
        printf("Got Error To Open %s File!\n", file_name);
        return errno;
    }

    printf("%s\n", buffer);

}

I want to read a file and save it to a string. (in C language)

8
  • 4
    You have snprintf(file_name, ...) but no memory allocated to file_name. The compiler should warn about that, don't ignore. Commented Dec 16, 2023 at 20:04
  • 1
    Please see No out of bounds error and Why doesn't my program crash when I write past the end of an array? Commented Dec 16, 2023 at 20:32
  • 2
    Warning: If the size of the file is the same as (or greater than) the buffer allocated, the buffer's contents will not be a properly terminated C string (i.e. ineligible to print with %s). Commented Dec 16, 2023 at 20:43
  • 3
    @EmadDeve Use the return value of fread(buffer, sizeof(char), BUFFER_SIZE, file) to know how much was read. Commented Dec 16, 2023 at 21:23
  • 2
    @chux-ReinstateMonica example Commented Dec 16, 2023 at 21:39

4 Answers 4

3

how to read a file and save content in a string?

  1. Open the file. Check for errors.
  2. Read entire file via fread() with a good size buffer, say 4K and sum the lengths returned.
  3. Continue step 2 until error or nothing read.
  4. Allocate sum + 1. Check for allocation success.
  5. Reread entire file with 1 fread() into the allocated buffer. Note the length returned.
  6. Close the file.
  7. Append a null character.
  8. If length is as expected, success, else failure.
  9. Return the allocated pointer or NULL on failure.
Sign up to request clarification or add additional context in comments.

8 Comments

it is a bit of a waste read the file in slices of 4K (or any size) just to compute the file size itself. You can get the file size at once, or you can just save each buffer read and advance the pointer in memory, extending the buffer size as needed...
@arfneto " You can get the file size at once" --> not in a portable fashion. fseek() trick & others have their portability limitations. Somewhat wasteful, yet for a rewind-able file, reading it 2x is completely portable. More advanced techniques would read & save a linked-list of blocks, (perhaps growling geometrically in size) which handles all files as a rewind is not needed, then reallocate once the lead block. Repeatedly calling realloc() leads to a potential O(n*n) solution whereas order O(n) is preferred - highly depends on the efficiency of realloc(), something not specified by C
stat is not portable? And if the block is really large it seems that we would have fewer transfers anyway. As for the efficiency of realloc is not it a simple wrapper over system services? get the new area, call sort of memory transfer if needed? But I believe I see your point anyway.
@Neil take into account that the C-FAQ is a collection of posts from the usenet between 1995 and 2005, never updated.
@chux-ReinstateMonica stat is present in Unix derivatives and Windows. It should mean something. And note that even a bad implemented realloc is using pointers from the metadata of malloc` and system calls from one of most optimized areas of any operating system: memory allocatation to processes. BTOH your idea to read the file twice is reading always from disk, and the laws of physics will show the difference: test your idea with a 4K buffer, and a 1GB file in a USB2 pendrive and maybe you will se a difference. Or just measure it with a trivial program.
|
1

One of the answers tells you to read the file twice but doesn't explain why. Here is the explanation.

A common way to determine the size of a file is by using fseek/ftell. Set the file's read pointer to the end of the file; then its position will tell the size of the file. This method is good for binary files (the ones which you open with mode "rb"), but for text files ("r") it is not accurate. In the common case, the only cause of the inaccuracy is conversion from \r\n to \n on Windows. Since it's OK to allocate a larger buffer, you can use this method to read the whole file.

char *read_file(char *file_name)
{
    FILE *file = fopen(file_name, "r");
    char *result = NULL;

    if (file == NULL)
        goto error;

    fseek(file, 0, SEEK_END);
    size_t size = (size_t)ftell(file);

    result = malloc(size + 1);
    if (result == NULL)
        return NULL;

    rewind(file);
    size_t real_size = fread(result, 1, size, file);
    if (ferror(file))
        goto error;

    result[real_size] = '\0';
    fclose(file);
    return result;

error:
    free(result);
    if (file)
        fclose(file);
    return NULL;
}

This commonly used method is not guaranteed to work: the output of ftell is technically unspecified when used like this; but in practice, it should work. It will fail in the following situations:

  • Wide character files (those from which you read wchar_t characters)
  • Very long files (with size greater than LONG_MAX, which may be equal to 2 GB)
  • Any unforeseen situation

2 Comments

Minor: if (result) not needed as free(NULL) is OK.
"It will fail in the following ..." --> better to then check return value of fseek(), ftell() to catch some of those reasons. Opening in binary mode has advantages/disadvantages.
1

You have many erroneous assumptions. I'll try to give you a little light on this darkness

  1. In the following code you are misusing snprintf:
    int opt;
    int file_name_customized = 0;
    char *file_name;

    while ((opt = getopt(argc, argv, "f:")) != -1) {
        switch (opt) {
            case 'f':
                snprintf(file_name, strlen(argv[2])+1, "%s", argv[2]);
                file_name_customized = 1;
                break;
            default:
                snprintf(file_name, EXAMPLE_FILE_SIZE, EXAMPLE_FILE);
        }
    }

    if (!file_name_customized)
    {
        snprintf(file_name, EXAMPLE_FILE_SIZE, EXAMPLE_FILE);
    }

The first two arguments to snprintf must be filled with a buffer pointer (a valid pointer, not an uninitialized one) and the buffer size (which has already been calculated from the optarg original) You are assuming the buffer will be built for you inside snprintf, and that is not possible (you pass the pointer by value, copying its value, so it's impossible for the routine to change the unknown ---and unpredecible--- value it could have: a correct approach (as you can know the string length of the command line argument) to do this before calling snprintf():

    int opt;
    int file_name_customized = 0;
    char *file_name = NULL;  /* initialize the buffer pointer to NULL */

    while ((opt = getopt(argc, argv, "f:")) != -1) {
        switch (opt) {
            case 'f':
                file_name = malloc(strlen(optarg)+1); /* see below, after this code snippet */
                if (file_name == NULL) { 
                    /* error, no allocatable memory, print error message
                     * and exit */
                    exit(1);
                }
                strcpy(file_name, optarg); /* copy the contents */
                file_name_customized = 1;
                break;
        }
    }

or simply, if you are not going to touch the file_name contents:

    int opt;
    int file_name_customized = 0;
    char *file_name = NULL;  /* initialize the buffer pointer to NULL */

    while ((opt = getopt(argc, argv, "f:")) != -1) {
        switch (opt) {
            case 'f':
                file_name = optarg; /* see below, after this code snippet */
                break;
        }
    }

(note: the reason for optarg is that you are using argv[2] which doesn't need to be the position of the argument of the -f option, you can specify options for getopt() in whatever order you like, so in case you have more options, you could specify other options before specifying -f and the option will be the argument following -f position (this is pointed by the getopt() global variable optarg, as documented in getopt(1)).

  1. The function read_file() doesn't know about the actual size of buffer. It just assumes it is BUFFER_SIZE, and this will be, in general, incorrect (if you reuse it for other buffers with different size). It would be better if you had passed the buffer size as an argument to the function (as snprintf() does in the standard library):
int read_file(char *buffer, size_t buffer_size, char *file_name)
{
    FILE *file;

    file = fopen(file_name, "r");

    if (file == NULL)
    {
        printf("Warning!!!");  /* an explanation on why the file could not be opened would have been appreciated, with the next instruction */
        fprintf(stderr, /* common to write errors to stderr, instead */
             "fopen \"%s\": %s\n", file_name, strerror(errno));
        return -1;  /* better return -1 (as the operating system does) to
                     * indicate an error, and positive to indicate how long
                     * was the file */
    }

    /* this will return the number of read chars */
    int nread = fread(buffer, sizeof(char), buffer_size, file);

    fclose(file);

    return nread;  /* so, you know how long the filled part of the buffer was */
}
  1. Next, in main(), you assume that the buffer has been filled and terminated with a '\0' character, as the %s formatting specifier requires, to know where the string ends. That is not true, your file can have '\0' characters, that will end prematurely the printing of the file, or worse, can have no '\0' characters and make printf() to go ahead and try to access past the buffer contents, and fail into undefined behaviour (this is probably what you appreciate sometimes)

In general, if you are working only with text files, you can assume your file will not have '\0' characters, and add it (but you need to do that, fread() doesn't) with something like:

    int read_bytes = read_file(buffer,
           sizeof buffer - 1,  /* reserve one cell at the end to add a '\0' char */
           file_name);  /* it should be filename */
    /* we can decide to treat errors here or in the function, as you prefer,
     * but it is better not to do it in both places. */
    if (read_bytes < 0) /* now the error definition is this */
    {
        printf("Got Error To Open %s File!\n", file_name);
        return errno;
    }

    buffer[read_bytes] = '\0';/* as read_file() now cannot read a file larger
                               * or equal than the buffer size, this 
                               * statement will never assign the 0 outside
                               * the buffer */
    /* now we can print it. */
    printf("%s\n", buffer);
}

But if you just want to print a file's contents, you can just do (far simpler solution, which requires no buffering, as stdio package already does buffering in a transparent way) and is not limited by the buffer size (so you can print file contents of files zillions of bytes larger)

#include <errno.h>  /* for errno variable */
#include <getopt.h> /* for getopt() and optarg */
#include <stdio.h>  /* for fgetc() and fputc() and all printf()s */
#include <stdlib.h> /* for exit() */
#include <string.h> /* for strerror() function */

int
main(int argc, char **argv)
{
    int opt;
    const char *file_name = NULL;
    FILE *f = stdin; /* by default, read from stdin */
    while ((opt = getopt(argc, argv, "f:")) != EOF) {
        switch (opt) {
        case 'f': file_name = optarg; break;
        }
    }
    if (file_name != NULL) { /* if we got a -f option with an argument */
        f = fopen(file_name, "r");
        if (!f) {
            fprintf(stderr, "Error: %s: couldn't fopen; %s\n",
                    file_name, strerror(errno));
            exit(1);
        }
    }

    /* now read and print it (at the same time) */
    int c;  /* WARNING: c ***MUST*** be integer, not a char, see fgetc() manual
             * page. */
    while ((c = fgetc(f)) != EOF) {
        putchar(c);
    }
    return 0;
} /* main */

This has some benefits:

  1. You don't need to do buffer management (something that stdio automatically does for you)
  2. You can use two interfaces to this program: a) specifying the file with a -f option or b) by redirecting standard input from the shell
  3. Simpler is better.

Or, if you want a function to do all the file stuff:

#include <errno.h>  /* for errno variable */
#include <getopt.h> /* for getopt() and optarg */
#include <stdio.h>  /* for fgetc() and fputc() and all printf()s */
#include <stdlib.h> /* for exit() */
#include <string.h> /* for strerror() function */

ssize_t print_file(char *name, FILE *out)
{
    FILE *in = fopen(name, "r");
    if (!in) return -1;
    int c;
    ssize_t count = 0;
    while ((c = fgetc(in)) != EOF) {
        fputc(c, out);
        count++;
    }
    fclose(in);
    return count;
}

int
main(int argc, char **argv)
{
    int opt;
    size_t total = 0;

    while ((opt = getopt(argc, argv, "f:")) != EOF) {
        switch (opt) {
        case 'f':
            ssize_t chars = print_file(optarg, stdout);
            fprintf(stderr,
                    "%s: %zd chars\n",
                    optarg, chars);
            total += chars;
            break;
        }
    }
    fprintf(stderr,
            "total: %zu chars\n",
            total);
    return 0;
} /* main */

this last approach (processing the file as we process the options) allows you to add multiple -f options, as in:

$ a.out -f a.c -f a.c -f a.c

will copy a.c three times to standard output (as unix cat command does)

Comments

0

The code is fragile in many points.

  • read_file() will fail if the file size is >= BUFFER_SIZE.
  • there is no warranty that there is a \0 to end the sequence of bytes read, unless the exact size of the file is BUF_SIZE-1, so
    char buffer[BUFFER_SIZE] = {"\0"};
    if (read_file(buffer, EXAMPLE_FILE) == 1)
    {
        printf("Got Error To Open %s File!\n", file_name);
        return errno;
    }
    printf("%s\n", buffer);

and the printf() call will fail.

Also

  • read_file() is called with EXAMPLE_FILE insead of file_name.
  • getopt() is a bit too much when the single purpose of the program is to load and print a string built with the contents of a file: just use the file name. And Windows does not have getopt

3 examples

Below are 3 simple examples of common ways to do this in C.

All 3 compiles under Microsoft compiler and gcc, and run ok.

The file used in the examples is 28.txt and has 28 bytes in size

01234
FGHIJ
56789
ABCDE

In many uses we need to change encoding of \n. I am now in Windows and the default content is

SO >
SO > od -x 28.txt
0000000 3130 3332 0d34 460a 4847 4a49 0a0d 3635
0000020 3837 0d39 410a 4342 4544 0a0d
0000034

SO >

and we seee that \n uses 2 bytes as 0x0d0a

example 1: read the file at once

#ifdef __linux__
  #define _GNU_SOURCE 
  #include <unistd.h>
#else
  #pragma warning(disable : 4013)
#endif

#include <errno.h>
#include <fcntl.h>
#include <iso646.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

long long int get_file_size(const char*);

int main(int argc, char** argv)
{
  const char* dflt_f_name = "28.txt";
  char        file_name[256];
  if (argc < 2)
      strcpy(file_name, dflt_f_name);
  else
      strcpy(file_name, argv[1]);
  int in = open(file_name, O_RDONLY);
  if (in < 0) return -1;  // could not open
  struct stat f_stats;
  if (fstat(in, &f_stats) < 0) return -2;  // fstat error
  // is it a regular file?
  if (not(f_stats.st_mode & S_IFREG)) return -3;
  if (f_stats.st_size < 1) return -4;
  fprintf(
      stderr, "size of file \"%s\" is %d\n", file_name,
      f_stats.st_size);
  off_t          size   = 1 + f_stats.st_size;
  unsigned char* buffer = malloc(size);
  if (buffer == NULL) return -5;
  int n = read(in, buffer, size);
  close(in);
  *(n + buffer) = 0; // terminate string
  fprintf(stderr,
      "%d bytes read into buffer\nstrlen(buffer) is "
      "%llu\n\n",
      n, strlen(buffer));
  // show on screen
  printf("Bytes:\t");
  for (size_t i = 0; i < n; ++i)
  {
      if (isprint(*(buffer + i)))
          printf("%c ", *(buffer + i));
      else
          printf("0x%X ", *(buffer + i));
  }
  printf("\n");    free(buffer);
  fprintf(stderr,"\n");
  return 0;
}

The program just

  • calls stat to get the file size
  • allocates a block of memory for the file
  • uses a single read to upload the file
  • terminates the string
  • shows the data

SO > ex1 28.txt
size of file "28.txt" is 28
24 bytes read into buffer
strlen(buffer) is 24

Bytes:  0 1 2 3 4 0xA F G H I J 0xA 5 6 7 8 9 0xA A B C D E 0xA


SO >

example 2: uses a buffer extended as need

This one uses an initial buffer that is expanded as needed. The idea is to allocate a buffer large enough to hold most of the expected files in a single read, but then extend it as needed for files larger than the initial block.

The buffer used here has just 4 bytes, it is just for test... Use something larger, like 1MB.


#define BUF_SIZE 4

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

int main(int argc, char** argv)
{
    const char* dflt_f_name = "28.txt";
    char        file_name[256];
    if (argc < 2)
        strcpy(file_name, dflt_f_name);
    else
        strcpy(file_name, argv[1]);

    FILE* in = fopen(file_name, "rb");
    if (in == NULL) return -1;

    size_t         b_size = 1 + BUF_SIZE;  // buffer
    size_t         f_size = 0;             // file
    unsigned char* buffer = malloc(b_size);
    if (buffer == NULL) return -2;
    size_t n       = fread(buffer, 1, BUF_SIZE, in);
    if (n < 1)
    {
        fclose(in), free(buffer);
        return -3;
    }
    f_size += n;
    if (n < BUF_SIZE)
    {
        buffer[n] = 0;  // terminate string
        fprintf(
            stderr,
            "\n\n\
    buffer size is: %llu\n\
    file size is: %llu\n\
    string size in memory is: %llu\n\n",
            b_size, f_size, strlen(buffer));
        fclose(in), free(buffer);
        return 0;
    }

    while (n > 0)
    {
        unsigned char* buf =
            realloc(buffer, b_size + BUF_SIZE);
        if (buf == NULL)
        {
            fclose(in), free(buffer);
            return -4;
        }
        buffer = buf;
        b_size += BUF_SIZE;
        n = fread(buffer + f_size, 1, BUF_SIZE, in);
        f_size += n;
        if (n == BUF_SIZE) continue;
        *(buffer + f_size) = 0;
        break;
    }
    fprintf(
        stderr,
        "\n\n\
    buffer size is: %llu\n\
    file size is: %llu\n\
    string size in memory os: %llu\n\n",
        b_size, f_size, strlen(buffer));

    printf("Bytes:\t");
    fclose(in);
    for (size_t i = 0; i < f_size; ++i)
    {
        if (isprint(*(buffer + i)))
            printf("%c ", *(buffer + i));
        else
            printf("0x%X ", *(buffer + i));
    }
    printf("\n");
    free(buffer);
    return 0;
}

The important part is inside the loop, the logic around realloc and the changes in buffer size.


SO > ex2 28.txt


    buffer size is: 33
    file size is: 28
    string size in memory os: 28

Bytes:  0 1 2 3 4 0xD 0xA F G H I J 0xD 0xA 5 6 7 8 9 0xD 0xA A B C D E 0xD 0xA

SO >

Example 3: uploading the file as an array of pointers to individual lines

In general this is the more useful way, since just after loading we can have direct access to any line of the original file. As an example, here the input file is sorted and then printed again.

These is the struct used to hold the file:


typedef struct
{
    size_t incr;   // increment size
    size_t limit;  // actual allocated size
    size_t size;   // size in use
    char** line;   // the lines

} Block;

Block* create_blk(size_t size, size_t increment);
Block* delete_blk(Block* block_to_go);
int    resize_blk(Block* block_to_go);
int    show_blk(Block* block, const char* msg);

Block* load_file(const char*);
int    cmp_line(const void*, const void*);
void   usage();

and the methods used to load a file, show its contents et. al.

The main program turns to simply:

  • get the file name and call load_file().
  • show the lines
  • sort them
  • show the lines again, sorted
  • free all
int main(int argc, char** argv)
{
    char msg[80] = {0};
    if (argc < 2) usage();
    Block* test = load_file(argv[1]);
    if (test == NULL) return -1;
    sprintf(
        msg, "\n\n==> Loading \"%s\" into memory", argv[1]);
    show_blk(test, msg);
    qsort(test->line, test->size, sizeof(void*), cmp_line);
    sprintf(
        msg, "\n\n==> \"%s\" after sort in-memory",
        argv[1]);
    show_blk(test, msg);
    test = delete_blk(test);
    return 0;
};

the complete code

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

typedef struct
{
    size_t incr;   // increment size
    size_t limit;  // actual allocated size
    size_t size;   // size in use
    char** line;   // the lines

} Block;

Block* create_blk(size_t size, size_t increment);
Block* delete_blk(Block* block_to_go);
int    resize_blk(Block* block_to_go);
int    show_blk(Block* block, const char* msg);

Block* load_file(const char*);
int    cmp_line(const void*, const void*);
void   usage();

int main(int argc, char** argv)
{
    char msg[80] = {0};
    if (argc < 2) usage();
    Block* test = load_file(argv[1]);
    if (test == NULL) return -1;
    sprintf(
        msg, "\n\n==> Loading \"%s\" into memory", argv[1]);
    show_blk(test, msg);
    qsort(test->line, test->size, sizeof(void*), cmp_line);
    sprintf(
        msg, "\n\n==> \"%s\" after sort in-memory",
        argv[1]);
    show_blk(test, msg);
    test = delete_blk(test);
    return 0;
};


int cmp_line(const void* one, const void* other)
{
    return strcmp(
        *((const char**)one), *((const char**)other));
}

Block* create_blk(size_t size, size_t increment)
{
    Block* nb = (Block*)malloc(sizeof(Block));
    if (nb == NULL) return NULL;
    nb->incr  = increment;
    nb->limit = size;
    nb->size  = 0;
    nb->line  = (char**)malloc(sizeof(char*) * size);
    return nb;
}

Block* delete_blk(Block* blk)
{
    if (blk == NULL) return NULL;
    for (size_t i = 0; i < blk->size; i += 1)
        free(blk->line[i]);  // free lines
    free(blk->line);         // free block
    free(blk);               // free struct
    return NULL;
}

int resize_blk(Block* nb)
{
    const size_t new_sz = nb->limit + nb->incr;
    char*        new_block =
        realloc(nb->line, (new_sz * sizeof(char*)));
    if (new_block == NULL)
    {
        fprintf(
            stderr,
            "\tCould not extend block to %zd "
            "lines\n",
            new_sz);
        return -1;
    }
    nb->limit = new_sz;
    nb->line  = (char**)new_block;
    return 0;
}  // resize_blk()

int show_blk(Block* bl, const char* msg)
{
    if (msg != NULL) printf("%s\n", msg);
    if (bl == NULL)
    {
        printf("Status: not allocated\n");
        return -1;
    }
    printf(
        "Status: %zd of %zd lines. [Incr. is %zd]:\n",
        bl->size, bl->limit, bl->incr);
    for (unsigned i = 0; i < bl->size; i += 1)
        printf("%4d\t%s", 1 + i, bl->line[i]);
    return 0;
}

Block* load_file(const char* f_name)
{
    if (f_name == NULL) return NULL;
    fprintf(stderr, "loading \"%s\" into memory\n", f_name);
    FILE* F = fopen(f_name, "r");
    if (F == NULL) return NULL;
    // file is open
    Block* nb = create_blk(4, 16);  // block size is 8
    char   line[200];
    char*  p = &line[0];
    p        = fgets(p, sizeof(line), F);
    while (p != NULL)
    {
        // is block full?
        if (nb->size >= nb->limit)
        {
            resize_blk(nb);
            printf(
                "Block extended for a total of %zd "
                "pointers\n",
                nb->limit);
        }
        // now copy the line
        nb->line[nb->size] = (char*)malloc(1 + strlen(p));
        strcpy(nb->line[nb->size], p);
        nb->size += 1;
        // read next line
        p = fgets(p, sizeof(line), F);
    };  // while()
    fclose(F);
    return nb;
}

void usage()
{
    fprintf(stderr, "Use: program file_to_load\n");
    exit(EXIT_FAILURE);
}

sample output


SO > ex3
Use: program file_to_load

SO > ex3 28.txt
loading "28.txt" into memory


==> Loading "28.txt" into memory
Status: 4 of 4 lines. [Incr. is 16]:
   1    01234
   2    FGHIJ
   3    56789
   4    ABCDE


==> "28.txt" after sort in-memory
Status: 4 of 4 lines. [Incr. is 16]:
   1    01234
   2    56789
   3    ABCDE
   4    FGHIJ

SO >

4 Comments

:D :D 3 examples in C with output, notes on the original program, and once more an answer I wrote is dv in the 1st 15 minutes. I need to do better!
Not sure how you can do better. On one hand, you should specify how to choose which method to use. This is very tricky (as you can see from comments on other answers). On the other hand, this answer is already too long; maybe split it to make it readable.
@anatolyg Thanks for taking the time to write. This is a long post due to my option of in fact posting the 3 complete examples with code, arguments and ouput: (1) uses stat and a single read call. (2) reuses a buffer and uses pointer arithmetic to load the file in slices, and (3) load a file into an array of lines. As I wrote above, sure the 3rd is more flexible, but may not be a solution for every case. Anyway each example has a title.
@LuisColorado In general any answer I post, maybe every question if I post one, is dv in a few minutes. Sort of a social thing, I believe. It is funny, or the posts are all really bad :D So I use to write a note on that. Maybe ex-employees, ex-whatever, it is a funny thing. Cheers. Guess what? Just happened again here in SO

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.