How would I read a text file in C?

88 views Asked by At

I have file.txt with

123456 2,00 beer
234567 2,50 milk
345678 3,30 ice cream

I want to put this info in my dynamic two-dimensional array:

char **dataBase;
dataBase = (char**)malloc(NUM_OF_PROD * sizeof(char*));
for(i = 0; i < NUM_OF_PROD; i++){
           dataBase[i] = (char*)malloc(MAX_BUFFER* sizeof(char));
}

But I don't know how. We have here 3 lines. If it was a C++, I would use getline() but in this situation I can't find a solution.

3

There are 3 answers

1
johanneshau On BEST ANSWER

I usually use the fgets() function to a file on a line-per-line basis (provided it is a text file).

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

#define LINELEN 200
#define NAMELEN  40

struct PRICELIST
{
  char item[NAMELEN];
  float price;
  unsigned int order_no;
  struct PRICELIST *next;
  struct PRICELIST *prev;
};

void list_print_node (struct PRICELIST *node)
{
  printf ("%d   %4.2f   %s\n", node->order_no, node->price, node->item);
}

void list_print (struct PRICELIST *head)
{
  printf ("Order #  Price  Item\n");
  printf ("------------------------------\n");
  while (head)
  {
    list_print_node (head);
    head = head->next;
  }
}

void list_delete (struct PRICELIST *head)
{
  if (head)
  {
    /* recursive call */
    list_delete (head->next);
    free (head);
  }
}

struct PRICELIST *list_read (char *filename)
{
  FILE *file;
  char line[LINELEN];
  struct PRICELIST *pricelist, *node, *prev;
  char *p;
  size_t len;

  file = fopen (filename, "r");
  if (file == NULL)
  {
    perror (filename);
    return NULL;
  }
  pricelist = NULL;
  prev = NULL;
  while (1)
  {
    if (fgets (line, sizeof(line), file) == NULL)
      break;

    /* eat the newline at the end of the buffer, be CR/CRLF agnostic .. */
    len = strlen (line) - 1;
    if (line[len] == '\r' || line[len] == '\n')
    {
      line[len] = '\0';
      len --;
    }
    if (line[len] == '\r' || line[len] == '\n')
      line[len] = '\0';

    /* allocate a new node in the list */
    node = malloc (sizeof (struct PRICELIST));
    if (node)
    {
      /* now use sscanf() for getting single elements */
      sscanf (line, "%d %f", &node->order_no, &node->price);

      /* since the item name might contain spaces this is not so easy .. */
      p = line;
      while (isspace(*p)) p++;
      while (isdigit(*p)) p++;
      while (isspace(*p)) p++;
      while (isdigit(*p)) p++;
      while (ispunct(*p)) p++;
      while (isdigit(*p)) p++;
      while (isspace(*p)) p++;
      strncpy (node->item, p, sizeof(node->item));
      node->next = NULL;

      /* if this is the first node of the list assign the head to it */
      if (pricelist == NULL)
        pricelist = node;

      /* append the new node to the end of the linked list */
      if (prev)
        prev->next = node;
      node->prev = prev;

      /* save it for the next entry */
      prev = node;
    }
  }
  /* we are done with the file, close it */
  fclose (file);
  return pricelist;
}

/* let's test it */
int main (int argc, char *argv[])
{
  struct PRICELIST *pricelist;

  if (argc < 2)
  {
    printf ("Usage: %s filename\n", argv[0]);
    return 0;
  }
  pricelist = list_read (argv[1]);
  if (pricelist)
  {
    /* print the list */
    printf ("This is the price list (filename '%s'):\n\n", argv[1]);
    list_print (pricelist);

    /* delete the list */
    list_delete (pricelist);
  }
  return 0;
}
3
JackWhiteIII On

In the comments you mentioned you were only concerned about actually reading a file. Here's how you'd go about reading a file (currently untested, binary mode):

#include <stdio.h>

int main()
{
    FILE *file = fopen("path/to/your/file/yourfile.txt", "rb");
    if(!file) return 1; //something went wrong!
    long size = fseek(file, 0, SEEK_END);
    char *buf = malloc(size);
    fread(&buf, size, 1, file); //read all contents, once
    fclose(file);
    free(buf); //because this is just an example
    return 0;
} 

For more info on reading a file, just do a quick google search and you'll find almost everything you're looking for.

1
jacwah On

You can implement your own version of getline using fgetc and realloc.

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

char *getline(FILE *file)
{
    size_t size = 16; // Size of memory allocated for line
    size_t len = 0;   // Characters read
    char *line = malloc(size);

    // Return NULL if memory allocation fails
    if (line == NULL)
        return NULL;

    for(;;) {
        int c;

        switch (c = fgetc(file)) {
            // If End Of File is met, return the line up until this point
            // if anything has been read
            case EOF:
            if (len == 0) {
                free(line);
                return NULL;
            }
            else {
                line[len+1] = '\0';
                return line;
            }

            case '\n':
            line[len+1] = '\0'; // NUL terminate the string
            return line;

            default:
            line[len++] = c;
        }

        // If the string plus NUL terminator is longer than size
        // double the size of line
        if (len + 1 >= size) {
            size *= 2;
            line = realloc(line, size);
            // Return NULL if memory allocation fails
            if (line == NULL)
                return NULL;
        }
    }
}

There are also many free/open source implementations of the same function that can be found online. For instance this GPL 2 one. If you are on a POSIX system (e.g. OS X or Linux) there is already a version of getline found in stdio.h.