【问题标题】:How modify a multidimensional pointer inside a function?如何修改函数内部的多维指针?
【发布时间】:2020-08-21 11:37:54
【问题描述】:

我有一个函数以这种方式使用mallocmemcpy 操作char***

// Convert a buffer full line to separated variables
int parseBufferToVariables(char ***variableContainer, char *bufferToParse, int maxVarSize) {
    int i = 0;
    // Get number of rows of the string
    int numberOfRows = 0;
    for (i = 0; bufferToParse[i] != '\0'; i++) {
        if (bufferToParse[i] == '\n')
            ++numberOfRows;
    }
    // Get number of columns of the string
    int numberOfColumns = 1;
    for (i = 0; bufferToParse[i] != '\n'; i++) {
        if (bufferToParse[i] == '\t')
            ++numberOfColumns;
    }
    // Allocate separated variable array
    size_t dim0 = numberOfColumns, dim1 = numberOfRows, dim2 = maxVarSize;
    variableContainer = malloc(sizeof *variableContainer * dim0);
    if (variableContainer) {
        size_t i;
        for (i = 0; i < dim0; i++) {
            variableContainer[i] = malloc(sizeof *variableContainer[i] * dim1);
            if (variableContainer[i]) {
                size_t j;
                for (j = 0; j < dim1; j++) {
                    variableContainer[i][j] = malloc(sizeof *variableContainer[i][j] * dim2);
                }
            }
        }
    }
    // Start parsing string to 3D array
    int init            = 0;
    int numberOfVars    = 0;
    int numberOfLines   = 0;
    int sizeOfVar       = 0;
    int position        = 0;
    char emptyArray[MAXVARSIZE] = {0};
    // Loop trought all lines
    i = 0;
    while (numberOfLines  < numberOfRows) {
        // Every delimiter
        if (bufferToParse[i] == '\t' || bufferToParse[i] == '\n') {
            // Size of the new sring
            sizeOfVar = i - init;
            // Set last \0 character in order to recognize as a proper string
            memcpy(&variableContainer[numberOfVars][numberOfLines], emptyArray, maxVarSize);
            // Copy the string to array
            memcpy(&variableContainer[numberOfVars][numberOfLines], &bufferToParse[position], sizeOfVar);
            // Handle pointers poisition
            init = i + 1;
            position += sizeOfVar + 1;
            // Handle when end of line is reached
            if (bufferToParse[i] == '\n') {
                numberOfVars = 0;
                numberOfLines++;
            }
        }
        i++;
    }
    return numberOfRows;
}

我试图用不同的方式来称呼它:

char*** container= {0};
parseBufferToVariables (&container, inputString, MAXVARSIZE);

char*** container= {0};
parseBufferToVariables (container, inputString, MAXVARSIZE);

即使我尝试在函数中调用char****

int parseBufferToVariables(char**** variableContainer, char* bufferToParse, int maxVarSize)

但我总是在parseBufferToVariables 函数之外调用char*** 出现段错误。 有任何想法吗?

【问题讨论】:

  • 四星编程,不错:)请学习Correctly allocating multi-dimensional arrays
  • 一般来说:如果你有三颗星***,你可能做错了什么。如果您有四颗星 ****,那么您肯定做错了什么。
  • 这种方法的一个问题是numberOfColumns 信息在返回时会丢失。调用代码缺少信息,无法知道索引到 container[][] 的距离。
  • 任何类似的方法来生成 3D 数组? (我用指针做这个,因为字符串大约 1gb)

标签: c arrays pointers malloc memcpy


【解决方案1】:

OP 正在争取 4 * 参数,但其他方法更好。

*s 的高度掩盖了一个关键的失败是代码需要以某种方式传达列(标签的数量)宽度。

此外,在形成 _strings_as 时,我没有看到确定的 null 字符 终止 第二个memcpy() 的大小没有限制 - 甚至可能会覆盖分配边界。


下面的想法是每个级别的分配都以null结尾。

csv = parse_file_string(const char *file_string);

返回时,当csv[line] == NULL时,没有更多的行了

csv[line][tab] == NULL 时,没有更多的字符串。

这种方法还允许每行使用不同数量的字符串。

调整算法,伪C代码

// return NULL on error
char ***parse_file_string(const char *file_string) {
  number_lines = find_line_count(file_string);
  char ***csv = calloc(number_lines + 1, sizeof *csv);
  if (csv == NULL) return NULL;

  for (line=0; line < number_lines; line++) {
    tab_count = find_tab_count(file_string);
    csv[line] = calloc(tab_count + 2, sizeof *(csv[line])); 
    // add NULL check

    for (tab=0; tab < tab_count; tab++) {
      char *end = strchr(file_string, '\t');
      csv[line][tab] = malloc_string(file_string, end);
      // add NULL check
      file_string = end + 1;
    }
    char *end = strchr(file_string, '\n');
    csv[line][tab++] = malloc_str(file_string, end); 
    // add NULL check
    file_string = end + 1;
    csv[line][tab] = NULL;

  }
  csv[line] = NULL;
  return csv;
}

用法

char ***container = parse_file_string(file_string);

for (line=0; container[line]; line++)
  for (tab=0; container[line][tab]; tab++)
     puts(container[line][tab]);

//free
for (line=0; container[line]; line++)
  for (tab=0; container[line][tab]; tab++)
     free(container[line][tab]);
  free(container[line]);
free (container)

【讨论】:

    【解决方案2】:

    如果支持,可以使用指向可变长度数组的指针。
    首先获取缓冲区内容的尺寸。这假设每一行都有相同数量的制表符。
    声明指针并分配内存。
    然后将缓冲区解析到分配的内存中。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void getdimension ( char *buffer, int *rows, int *cols, int *size) {
        int maxsize = 0;
        *rows = 0;
        *cols = 0;
        *size = 0;
        while ( *buffer) {//not the terminating zero
            if ( '\n' == *buffer) {
                if ( ! *rows) {//no rows counted yet
                    ++*cols;//add a column
                }
                ++*rows;
                if ( maxsize > *size) {
                    *size = maxsize;
                }
                maxsize = 0;
            }
            if ( '\t' == *buffer) {
                if ( ! *rows) {//no rows counted yet
                    ++*cols;
                }
                if ( maxsize > *size) {
                    *size = maxsize;
                }
                maxsize = 0;
            }
            ++maxsize;
            ++buffer;
        }
        if ( '\n' != *(buffer - 1)) {//last character is not a newline
            ++*rows;
            if ( maxsize > *size) {
                *size = maxsize;
            }
        }
    }
    
    void createptr ( int rows, int columns, int size, char (**ptr)[columns][size]) {
        if ( NULL == ( *ptr = malloc ( sizeof **ptr * rows))) {
            fprintf ( stderr, "malloc problem\n");
            exit ( EXIT_FAILURE);
        }
        for ( int line = 0; line < rows; ++line) {
            for ( int tab = 0; tab < columns; ++tab) {
                (*ptr)[line][tab][0] = 0;
            }
        }
    }
    
    void parsebuffer ( char *buffer, int rows, int columns, int size, char (*ptr)[columns][size]) {
        int eachrow = 0;
        int eachcol = 0;
        int eachsize = 0;
    
        while ( *buffer) {
            if ( '\n' == *buffer) {
                ++eachrow;
                eachcol = 0;
                eachsize = 0;
            }
            else if ( '\t' == *buffer) {
                ++eachcol;
                eachsize = 0;
            }
            else {
                ptr[eachrow][eachcol][eachsize] = *buffer;
                ++eachsize;
                ptr[eachrow][eachcol][eachsize] = 0;
            }
            ++buffer;
        }
    }
    
    int main ( void) {
        char line[] = "12\t34\t56\t78\t!@#\n"
        "abc\tdef\tghi\tjkl\t$%^\n"
        "mno\tpqr\tstu\tvwx\tyz\n"
        "ABC\tDEF\tGHI\tJKL\tMNOPQ\n";
        int rows = 0;
        int columns = 0;
        int size = 0;
    
        getdimension ( line, &rows, &columns, &size);
        printf ( "rows %d cols %d size %d\n", rows, columns, size);
    
        char (*ptr)[columns][size] = NULL;//pointer to variable length array
    
        createptr ( rows, columns, size, &ptr);
    
        parsebuffer ( line, rows, columns, size, ptr);
    
        for ( int row = 0; row < rows; ++row) {
            for ( int col = 0; col < columns; ++col) {
                printf ( "ptr[%d][%d] %s\n", row, col, ptr[row][col]);
            }
        }
    
        free ( ptr);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-11-13
      • 2022-01-07
      • 1970-01-01
      • 2011-06-23
      • 2019-03-18
      • 2016-03-30
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      相关资源
      最近更新 更多