0
char *lessons[100];
FILE *lessonsptr;

lessonsptr = fopen("lessons.txt", "r");

fscanf(lessonsptr, "%d", &N);
char str[100];
while (!feof(lessonsptr))
{
    fgets(str, 100, lessonsptr);
    lessons[i] = str;
    i++;
}

fclose(lessonsptr);

In the while block, I want to read a string from a file and store it in lessons[i], but this code scans with newline. I tried other ways like using fscanf and %[^\n], but they won't work. How can I get it work ?

p.s. The first line in lessons.txt is the number of strings. That's why I read an integer in line 6.

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
  • If you mean it reads in the newline into the string, then just let it, and remove the newline afterwards – The Archetypal Paul Dec 27 '14 at 22:17
  • Also, you need to allocate space for each lesson, copy the string from `str` to this new space. Right now, all entries in the lessons array will end up with the value `str`, which is just the address of the `str` array, which will just contain the final lesson read from the file. – The Archetypal Paul Dec 27 '14 at 22:19
  • And you don't read N entries, but read as many as the file contains. If that's more than 100, you will walk off the end of the lessons array... And you don't check the result of fopen to see if it worked, etc, etc. – The Archetypal Paul Dec 27 '14 at 22:20
  • are you allowed to use getline()? – Jasen Dec 27 '14 at 22:21
  • 3
    [while !feof() is always wrong](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong/5432517#5432517) – user3386109 Dec 27 '14 at 22:23
  • if the number at the start is on a line by itself the scanf format should be "%d\n" – Jasen Dec 27 '14 at 22:56

3 Answers3

2

Your code is wrong in two spots:

  • You should not be reading while(!feof(...)), and
  • You need to make copies of the buffer as you go

You can do it like this:

while (fgets(str, 100, lessonsptr)) {
    lessons[i] = malloc(strlen(str)+1); // Add 1 for '\0' terminator
    strcpy(lessons[i], str); // Copy the string into the allocated space
    i++;
}

Alternatively, since you know how many lines there would be in your file, you could make a for loop to N:

for (int = 0 ; i != N ; i++) {
    fgets(str, 100, lessonsptr);
    lessons[i] = malloc(strlen(str)+1);
    strcpy(lessons[i], str);
}

Note that since dynamic memory allocation is used, you need to call free(lessons[i]) in a loop at the end of your program.

Another note: you could use strdup, too, but it is not part of C standard library.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1
there were many problems with the code.
the following compiles cleanly
However, I have not run it.

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

#define MAX_LINE_LENGTH (100)

void cleanup( char **, int );

int main()
{
    int N = 0; // count of data line in file

    FILE *lessonsptr;

    if( NULL == (lessonsptr = fopen("lesson.txt", "r") ) )
    { // then fopen failed
        perror( "fopen failed for lesson.txt" );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    // get count of following lines
    if( 1 != fscanf(lessonsptr, " %d \n", &N) )
    { // then, fscanf for line count failed
        perror( "fscanf failed for line count" );
        fclose(lessonsptr);
        exit( EXIT_FAILURE );
    }

    // implied else, fscanf for line count successful

    char **lessons = NULL;
    int i = 0; // loop counter
    if( NULL == (lessons = malloc(N*sizeof(char*)) ) )
    { // then malloc failed
        perror( "malloc failed for lessons");
        fclose(lessonsptr);
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful for lessons

    // set all lessons[] to NULL
    memset( lessons, 0x00, (N*sizeof(char*) ) );

    for( i=0; i< N; i++)
    {
        if( NULL == (lessons[i] = malloc(MAX_LINE_LENGTH) ) )
        { // then, malloc failed
            perror( "malloc failed for lessons[]" );
            fclose(lessonsptr);
            cleanup( lessons, N );
            exit( EXIT_FAILURE );
        }

        // implied else, malloc successful for lessons[i]

        // clear the malloc'd memory
        memset(lessons[i], 0x00, MAX_LINE_LENGTH );
    }

    char str[MAX_LINE_LENGTH] = {'\0'};

    for( i = 0; i<N; i++)
    {
        if( NULL == fgets(str, MAX_LINE_LENGTH, lessonsptr) )
        { // then file did not contain enough lines
            perror( "fgets failed" );
            fclose(lessonsptr);
            cleanup( lessons, N );
            exit( EXIT_FAILURE );
        }

        // implied else, fgets successful

        // copy line to where lessons[i] points
        memcpy( lessons[i], str, MAX_LINE_LENGTH );

        // prep for next input line
        memset( str, 0x00, MAX_LINE_LENGTH );
    } // end for

    fclose(lessonsptr);
    cleanup( lessons, N );
    return(0);
} // end function: main

void cleanup( char **lessons, int N )
{
    int i; // loop counter
    for(i=0; i<N; i++)
    {
        free(lessons[i]);
    }
    free(lessons);
} // end function: cleanup
user3629249
  • 16,402
  • 1
  • 16
  • 17
0

here's one way:

    char str[100][100];
    while (!feof(lessonsptr) && i<100 )
    {
        if( !fgets(str[i], 100, lessonsptr))
            break;
        lessons[i] = str[i];
        i++;
    }

if you're allowed getline this is probably better:

    while (!feof(lessonsptr) && i<100)
    {
        if(0>( lessons[i] = getline(NULL,NULL,lessonptr)))
              break;
        i++;
    }

but since you have the number of lessons in the variable N (you're supposed to use lowercase for variables in C) you could do the initialisation like this.

char **lessone=NULL;  
int (*str)[100]; // if not using getline()

 /*
 ...
 */

    fscanf(lessonsptr, "%d\n", &N);  // need \n to read a whole line
    lessons=calloc(sizeof(char*),N);

    str=malloc(100*N); // if not using getline()

    while (!feof(lessonsptr) && i<N )
Jasen
  • 11,837
  • 2
  • 30
  • 48
  • seems like noone likes this – Jasen Dec 27 '14 at 22:53
  • 1
    Code's use of `feof()` is wrong. Code needs to test the result of `fgets()`. – chux - Reinstate Monica Dec 28 '14 at 06:44
  • Minor bits: 1) The `'\n'` in `fscanf(lessonsptr, "%d\n", &N);` consumes more than a `'\n'` at the end of the line but any and all subsequent white-spaces - and that does not match the comment. Curiously of the 3 uses of `feof()`, this one works because of the `'\n'`. 2) `calloc(size_t nmemb, size_t size)` is usually called the other way around `calloc(N, sizeof(char*));` - Hmmm, I wonder if the order could make a difference. 3) You may like the, IMO, the easier to code, understand and maintain allocation call style of `lessons = calloc(N, sizeof *lessons);` 4) BTW: NMDV. – chux - Reinstate Monica Dec 28 '14 at 12:05
  • With checking the result of `fgets()` and `getline()`, code could be simplified and not use `feof()`: `while (i<100 && fgets(str[i], 100, lessonsptr) != NULL) { lessons[i] = str[i]; i++; }`. – chux - Reinstate Monica Dec 28 '14 at 12:11