buffering a set of lines from a file and storing i

2020-04-21 03:32发布

问题:

This might be a very inefficient way to do it, but its sort of working

This code reads through a file, stores 8 line of text at a time in a global array (Would like a better option to do this if possible ) and dispatches for further processing.

here's the code

int count = 0;             //global
char *array_buffer[8];     //global

void line(char *line_char)
{

    int lent = strlen(line_char);
    array_buffer[count] = line_char;

    printf("%d\n",count);

    if (count == 8)
    {

        int row,col;
        for(row = 0; row<count; row++){
            printf("%d\n",row);
            for(col = 0; col<=lent; col++) {
                printf("%c", array_buffer[row][col]);
            }
        printf("\n");   
        }
    count = 0;
    }

    count++;
}



int main(int argc,char **argv)
{

    clock_t start = clock();

    FILE *fp = fopen(argv[1], "r");
    if(fp == NULL )
    {
        printf("Couldn't open file %s",argv[1]);
    }
    char buff[512];

    while (fgets(buff, 512, fp) != NULL )
    {
        line(buff);             /*sending out an array having one line*/
    }

    return 0;
}

The issue is that while printing out the contents of array_buffer, its printing out the last line in the buffer 8 times. (i.e. the 8th line its reading in every cycle). Its pretty obvious that

array_buff[0]
....
array_buff[7]

all point to the address of line 8

any help in solving this ? I know it might not be the correct way to buffer something at all !

回答1:

You have a stale pointer, here I will explain

while (fgets(buff, 512, fp) != NULL )
{
    //buff updated
    line(buff);
    //...
    //inside of the line function
        somepointertopointers[currIndex]=buff;

now it is looking at the location at buff, so all of the elements are looking at the same location, you need to copy the chars, or make a longer buffer and make sure you are updating the location the pointer is looking at, you can make 8 separate char[] pointers as well

This will give you the result you want

buff[512][8];
char** curr = buff;
while(fget(*curr,512,fp)!= NULL)
{
     line(*curr);
     curr++;
}

or alternatively you could allocate the buffer that is passed

#def BUFF_SIZE 512
#def BUFF_ARRAY_LEN 8


//put this somewhere before calling line 
//to initialize your array_buffer
for(i=0;i<BUFF_ARRAY_LEN;i++)
{
    array_buffer[i]=NULL;
}

...

//update in function line
//makes more sense to just use 
//the max len of a line
if(array_buffer[count] == NULL)
    array_buffer[count]=(char*)malloc(sizeof(char)*BUFF_SIZE);
strcpy(array_buffer[count],line_char);

...

//you will also need to
//clean up after you are 
//done with the memory
for(i=0;i<BUFF_ARRAY_LEN;i++)
{
    free(array_buffer[i]);
}


回答2:

The problem with your approach that leads to the behavior that you see is that your code never copies the data from the buffer. This line

array_buffer[count] = line_char;

puts a pointer to the same char buff[512] from main at all eight locations. Subsequent calls to fgets override the content of previous reads, so you end up with eight copies of the last line.

You can fix this issue by making a copy, e.g. with strdup or by allocating memory with malloc and making a copy. You need to free everything that you allocate, though.



回答3:

void line(char *line_char){
    if (count == 8){
        int row,col;
        for(row = 0; row<count; row++){
            printf("%2d:",row);
            printf("%s", array_buffer[row]);
            free(array_buffer[row]);
        }
        count = 0;
    }
    int lent = strlen(line_char);
    array_buffer[count] = malloc((lent + 1)*sizeof(char));
    strcpy(array_buffer[count], line_char);
    //printf("%d\n", count);
    count++;
}