Markus
Markus

Reputation: 2062

C read lines of file to array prints only first character from line

I try to read the lines from an txt file to an array in C. By method to load the lines looks like this:

char *loadNames(FILE *file) {
    char *list = malloc(42);
    int BUFFER_SIZE = {256};
    char *buffer = malloc(BUFFER_SIZE);
    char count;

    while (fgets(buffer, BUFFER_SIZE, file)) {
        list[count] = *buffer;
        count++;
    }

    return list;
}

At a later point in my code I call the function and print all values.

char *names = loadNames(file);
for (int i = 0; i < 41; i++) {
  printf("%c\n", names[i]);
}

The file contains a name in each line. The problem is that the current code only prints the first character of each name.

A
B
C

instead of

Anna
Berry
Chanel

If I print the value of buffer in the while statement from snippet #1 the full names are displayed.

What can I do to get the full names instead of only the first letters in my array?

Upvotes: 0

Views: 460

Answers (3)

Jabberwocky
Jabberwocky

Reputation: 50775

You want this:

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

#if 0    // uncomment this if strdup is not available on your platform
// Duplicate a string (google strdup for more information)
char **strdup(const char *source)
{
  char* newstring = malloc(strlen(source) + 1);
  if (newstring)
    strcpy(newstring, source);

  return newstring;
}
#endif


char **loadNames(FILE* file) {
  char **list = malloc(sizeof(char*) * 42); // you want 42 pointers to char, not 42 chars
  const int BUFFER_SIZE = 256;        // just 256, not {256}
  char buffer[BUFFER_SIZE];           // no need to allocate dynamically here
  char count = 0;                     // you forgot to initialize to 0

  while (fgets(buffer, BUFFER_SIZE, file)) {
    list[count] = strdup(buffer);      // you need to duplicate the string,
                                      // not just assign a char
    count++;
  }

  return list;
}

There are still a problem with this code:

  • if there are more than 42 lines in the file, you're in trouble.
  • loadnames returns a pointer to an array of pointers, each of which point to a line of the file. The problem is once you've called loadNames you don't know how many lines have actually been read.
  • there is no error checking whatsoever for brevity.

Upvotes: 2

Ed Heal
Ed Heal

Reputation: 60007

In addition to the answers above that fixes your implementation of loadNames

You need

char **loadNames(FILE *file) {
  // See the other answers
}

Then

char **names = loadNames(file);

for(i=0; list[i] != NULL; i++) {
    printf("%c\n", names[i]);
}

Upvotes: 0

Serge Ballesta
Serge Ballesta

Reputation: 148910

C language has no true notion of strings. But the standard library defines strings as null terminated char arrays where char is the single character type. So what you want is closer to:

#define BUFFER_SIZE 256

char *loadNames(FILE *file) {
    char **list = malloc(42 * sizeof(char *));      // array of pointers
    char buffer[BUFFER_SIZE];
    char count = 0;                // never forget initialization

    while (fgets(buffer, BUFFER_SIZE, file)) {
        list[count] = strdup(buffer);          // allocate a new buffer
        count++;
    }
    list[count] = NULL;                        // sentinel value

    return list;
}

At the end, you should free all the allocated arrays:

for(i=0; i<42; i++) {
    if (list[i] == NULL) break;         // stop at the sentinel
    free(list[i]);
}
free(list);

Upvotes: 2

Related Questions