arrayscmultidimensional-array

How to convert a 1 dimensional array buffer to a 2 dimensonal format


I have this intermediary buffer that has the entire contents of a file: char *intermediary_buffer

I need to move this to a different 2D buffer: char **final_buffer Where a new row is started every time the \n escape sequence is detected in the original buffer. Effectively storing each line of the file in its own row.

I thought about using a for loop, where it would scan through the intermediary buffer and copy every part leading up to the \n escape sequence in a row:

for(int i = 0; i < file_size; i++){
  if(intermediary_buffer[i] == '\n'){
    // Copy all leading up to `\n` to new 2D buffer
  }
}

I get lost after creating the for loop . . .

How can I achieve this in a fast way?


Solution

  • One option is to iterate through the memory block that contains the file contents using strcspn. Allocate pointers and allocate memory to each pointer. realloc can allocate pointers and strndup will handle the allocation of memory to each pointer and copy data to the allocated memory.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define SIZE 8129
    
    char **strpdlm ( char *source, char *delim) {
        char **target = NULL; // pointer to pointer
        int span = 0;
        int count = 0;
    
        while ( source && *source) {
            span = strcspn ( source, delim); // count to next delimiter
    
            char **temp = NULL;
            if ( NULL == ( temp = realloc ( target, sizeof target * ( count + 2)))) { // allocate two more pointers
                fprintf ( stderr, "realloc problem\n");
                return target;
            }
    
            target = temp;
    
            if ( NULL == ( target[count] = strndup ( source, span + 1))) { // allocate memory and copy to one pointer
                fprintf ( stderr, "strndup problem\n");
                return target;
            }
    
            ++count;
            target[count] = NULL; // the other pointer serves as sentinel NULL
    
            source += span; // advance pointer
            if ( *source) { // not at terminating zero
                ++source; // advance past delimiter
            }
        }
    
        return target;
    }
    
    char *readcontents ( char *filename) {
        char *contents = NULL;
        char buffer[SIZE] = "";
        size_t size = 0;
        size_t bytes = 0;
        FILE *pf = NULL;
    
        if ( NULL == ( pf = fopen ( filename, "r"))) {
            perror ( filename); // why the file could not be opened
            return contents;
        }
    
        while ( 0 < ( bytes = fread ( buffer, 1, sizeof buffer, pf))) { // read a buffer from file
            char *temp = NULL;
            if ( NULL == ( temp = realloc ( contents, size + bytes + 1))) { // reallocate contents for buffer
                fprintf ( stderr, "problem realloc\n");
                fclose ( pf);
                return contents;
            }
            contents = temp;
            memmove ( contents + size, buffer, bytes); // append buffer to contents
            size += bytes;
            contents[size] = 0; // terminating zero
        }
    
        fclose ( pf);
    
        return contents;
    }
    
    int main ( void) {
        char *filename = "file.txt";
        char *contents = NULL;
        char *delim = "\n";
        char **lines = NULL;
    
        if ( NULL == ( contents = readcontents ( filename))) {
            fprintf ( stderr, "no contents in file %s\n", filename);
            return 1;
        }
    
        printf ( "contents\n%s\n", contents);
    
        if ( NULL == ( lines = strpdlm ( contents, delim))) {
            free ( contents);
            fprintf ( stderr, "strpdlm returned NULL\n");
            return 1;
        }
    
        free ( contents); // free contents
    
        size_t each = 0;
        printf ( "\nlines\n");
        while ( lines[each]) { // not at sentinel NULL
            printf ( "lines[%zu]%s", each, lines[each]);
            ++each;
        }
        printf ( "\n");
    
        each = 0;
        while ( lines[each]) { // not at sentinel NULL
            free ( lines[each]); // free pointer memory
            ++each;
        }
        free ( lines); // free pointers
    
        return 0;
    }