0

I am beginner.I have a file which has lines like MONSTER,ERRTU,14,2 . when i tried to read the lines and store them into a dynamic memory allocated array. it seems like it worked at first but then when i tried to print the elements of it later , it doesnt work properly.Is it about using char * ? How can I fix this problem?

here my code is;

char *lines_ptr;
line_ptr=(char *)malloc(line*(sizeof(char)*100));   
int i=0;

if (fptr==NULL){

    printf("file could not be opened.");
}
else{ 

//line=number of lines
while(!feof(fptr)){
    for(i=0;i<line;i++){

        fscanf(fptr,"%s",lines_ptr+i);

        printf("%s\n",(lines_ptr+i));
    }
}

printf("%s",(lines_ptr));//this part shows me i did something wrong.

}  

here is my output;

   HERO,DRIZZT,8,3
   HERO,CATTIE,6,3
   HERO,BRUENOR,10,1
   HERO,WULFGAR,12,4
   MONSTER,TROLL,4,3
   MONSTER,GOBLIN,1,3
   MONSTER,UNDEAD,1,1
   MONSTER,VERMIN,3,2
   MONSTER,MINDFLAYER,10,2
   MONSTER,ERRTU,14,2
   HHHHMMMMMMONSTER,ERRTU,14,2 

why does it happen?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • In C, it's frowned upon to cast the return of malloc, as is while(!feof(file)) – JGroven Mar 07 '18 at 17:24
  • @JGroven What should change it into? –  Mar 07 '18 at 17:27
  • Take a look [here](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). – JGroven Mar 07 '18 at 17:28
  • @JGroven So you think the only problem is that in the code you see above? –  Mar 07 '18 at 17:31
  • regarding: `line_ptr=(char *)malloc(line*(sizeof(char)*100));` 1) in C, the returned type from any of the heap allocation functions ( `malloc`, `calloc`, `realloc` ) is `void*`. I.E. it can be assigned to any other pointer. Casting just clutters the code, making it more difficult to understand, debug, etc. 2) Always check (!=NULL) the returned value to assure the operation was successful. 3) the expression: `sizeof(char)` is defined in the standard as 1. Multiplying anything by 1 has absolutely no effect. – user3629249 Mar 07 '18 at 18:46
  • regarding: `while(!feof(fptr)){` the function: `feof()` does not do what the code is expecting. suggest elimination of the `for()` statement and controlling the loop via the returned value from `fscanf()` – user3629249 Mar 07 '18 at 18:49
  • regarding: `fscanf(fptr,"%s",lines_ptr+i);` this reads ALL the lines from the file into the same location in memory. So all but the last line is lost. Also, `'%s" will stop inputting when it encounters any `white space` character. So if any line contains a space, the rest of the line will not be input during that specific call to `fscanf()` – user3629249 Mar 07 '18 at 18:54

4 Answers4

3
HHHHMMMMMMONSTER,ERRTU,14,2 //why does it happen?

What you do is as follows.

You read to the line buffer, but every time you move the beginning of the text by 1 character. So when you come back and print beginning of the buffer you will get all the first characters of all previously read lines plus last read line.

sg7
  • 6,108
  • 2
  • 32
  • 40
0

you incorrectly use "line_ptr" (and so many other stuff ...).

From what I understand, it's seem you whant to load the entire file into "line_ptr", each file's line being in "line_ptr[i]".

If that so, then I advise you to take your time and do really simple code, and after, make it more complicated.

For instance, dont use malloc : with your current code, it's useless anyway.

Let's say you have a file with NB_LINE line at maximum, each line having NB_MAX_CHAR character at maximum.

#define NB_LINE_MAX 50
#define NB_CHAR_MAX 100

char   lines[NB_LINE_MAX][NB_CHAR_MAX];
size_t nbLines = 0;

for (nbLines = 0; fgets(lines[nbLines], NB_CHAR_MAX, fptr); ++nbLines) {
  // Nothing to do, fgets do it for us
}

if (!feof(fptr)) {
  // problem while reading :/
}


printf("Test :\");
for (size_t i = 0; i < nbLines; ++i) {
  printf("%d : %s", i, lines[i]);
}

Does this code work ? If yes, try to improove it by removing NB_LINE_MAX first (then you can have at many line you want in your file, not only 50) and after, try to remove NB_CHAR_MAX (then you can have a line without char limitation).

Misc remark :

  • sizeof(char) is alway 1, always. So you can delete it from your malloc.
  • fscanf(fptr,"%s",lines_ptr+i) is dangerous. %s will read at many char it want, so if he read 500 char but lines_ptr can only hold 100 of them, it will write somewhere not good, and you will probably have SIGSEV runtime crash.
  • while(!feof(fptr)) already say by another, but it's note how you use feof.
Tom's
  • 2,448
  • 10
  • 22
  • I understand thank your for your help. I need to use malloc and i am trying to learn it . how can i use fgets() with malloc? –  Mar 07 '18 at 18:00
  • fgets have nothing to do with malloc. If you want to read an unknow number of something (actually, it's line from a file), there are two commom approach of this : the first si to retrieve the total number of "something", allocate, then fill it. The second approach is to fill it, and if you don't have enougth space, reallocate it. Each one have pros and cons, depending on how "easy/possible/not punishing" it is to firstly retrieve the total number of something you need to allocate, and other implemtation-context thing. Give it a try with the first method (in your case, it's the simpliest). – Tom's Mar 08 '18 at 08:15
0

There are some mistakes you are doing.First look carefully what you are messing with in the picture.Suppose there are two line in the input hello and world,while taking the first input line_ptr starts from 0,so it will store hello from 0 to 4 but in second line line_ptr is incremented to 1 so it will store world from 1 to 5 and this will go on if more lines are there. enter image description here NOTE: Always check the return value of scanf() or fscanf()

For taking line as a input in c, you should use Array of pointers like char *lineptr[MAXLINE];

 int readline(char* lineptr[])
 {
      char line[1000];
      for(i=0;i<MAXLINE;i++){
           if(fscanf(stdin,"%s",line)){
              char *temp=malloc((strlen(line)+1)*sizeof(char));
              strcpy(temp,line);
              lineptr[i]=temp;  
           }
      }
      return i; 
 }

This function will read a line in a variable line, then it will allocate memory for that line in temp and lineptr[i] will point to that new line.It returns number of lines read.

krpra
  • 466
  • 1
  • 4
  • 19
0

the following proposed code:

  1. always reads the whole line from the file
  2. properly checks for errors
  3. properly places the read in data in the 'malloc'd array
  4. eliminates the clutter from the code
  5. eliminates the use of a 'magic' number in the code

and now the proposed code

    if ( !fptr )
    {
        perror( "file could not be opened." );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    #define MAX_LINE_LEN 100

    //size_t line=number of lines
    char *line_ptr = malloc( line * MAX_LINE_LEN ));
    if( !line_ptr )
    {
        perror( "malloc failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    size_t i = 0;
    // Note: '%[^\n]' reads to end of line, but not the newline char
    //      AND appends a NUL byte to the end of the input
    //      '%*c' reads and discards the newline char
    // Note: using the '%*c' requires the last line in the file ends with a newline char
    //      otherwise the last call to `fscanf()` will 'hang' looking for the final newline
    while( i < lines && 1 == fscanf(fptr,"%[^\n]%*c", line_ptr+(MAX_LINE_LEN*i) ) )
    {
        printf( "%s\n", line_ptr+(MAX_LINE_LEN*i) );
        i++;
    }
user3629249
  • 16,402
  • 1
  • 16
  • 17