0

我必须实现一组分配、修改和释放 c 样式字符串的二维数组的方法。我不能使用字符串、向量或任何 stl 容器。

getNewMat :

char*** getNewMat(int w, int h){
    char*** newMat = new char**[h];
    for(int i = 0 ; i < h ; i++){
        newMat[i] = new char*[w];
        for(int j = 0 ; j < w ; j++)
            newMat[i][j] = NULL;
    }
    return newMat;
}

填充垫

void fillMat(char***mat, int x, int y, char* newEl){
    mat[y][x] = newEl; //this will produce a segfault (even with good index)
}

表演垫:

void showMat(char*** mat, int w, int h){
    for(int i = 0 ; i < h ; i++){
        for(int j = 0 ; j  < w ; j++)
            cout << mat[i][j];  
    }
    cout << endl;
}

那么,谁能告诉我这有什么问题?

4

3 回答 3

0
  1. newMat[i][j] = NULL- 这是个坏主意。在showMat您将尝试取消引用 NULL 指针 - 这是 UB,可能会导致段错误。

  2. char*- 它不是一个字符串 - 它只是一个指向 char 的指针,它可能指向内存位置,可以是字符串的开头。如果你想像处理字符串一样使用它,你也应该为它分配内存。

  3. mat[y][x] = newEl- 这也是个坏主意。正如我已经说过的,char*不是字符串,因此,您不能只使用赋值运算符将数据从一个复制C-string到另一个。您应该使用std::copystd::strncpy

  4. 不要忘记在使用后释放分配的内存。

你应该实现你自己的string类 - 这是更好的解决方案,我可以在那里看到。至少,因为它更简单,更容易理解。

于 2013-05-04T13:02:20.173 回答
0

在你的fillMat方法中,你这样做:

mat[y][x] = newEl;

其中xy是数组的两个等级的维度。该行将导致分段错误,因为您超出了数组的范围。mat索引从 0 到length - 1并设置为x并且y在数组边界之外变为 1。

也许您打算循环并设置它们:

for (int i = 0; i < y; ++i)
{
     for (int k = 0; k < x; ++k)
         mat[i][k] = newEl;
}

此外,在你的showMat函数中,你有这个:

cout << showMat[i][j];  

我认为您的意思是mat

cout << mat[i][j];  
于 2013-05-04T12:50:26.010 回答
0

我必须实现一组分配、修改和释放 c 样式字符串的二维数组的方法。...剪断...所以,谁能告诉我这有什么问题?

“c 风格的字符串”不是一种类型。它是类型中数据的表示。'\0'以 -结尾的字符串通常存储在char数组中,但您也可以轻松地将其存储在unsigned int数组中。例如:

unsigned int message[32] = { 0 };
strcpy((char *) message, "Hello, world!");
printf("%s\n", (char *) message);

我不鼓励这样的编程,但好处可能看起来微乐观。也可以将字符串存储在不是数组的东西中。考虑 achar可能适合存储空字符串:

char x = '\0';
printf("%s\n", &x);

char当您说“c 样式字符串的二维数组”时,假设您的意思是“数组的数组”是合理的。让我们继续朝着这个方向前进。


我对 C++ 了解不多,但是有一个数组属性列表,您在尝试模仿实际数组时可能没有考虑过这些属性。我将使用assert离子总结这些:

#define x 7
#define y 13
#define z 1
char foo[x][y][z] = { 0 };
assert((char *) foo == foo[0]);
assert(sizeof foo == (char *) &foo[1] - (char *) &foo[0]);
assert(sizeof foo == x * y * z);

我不确定您是否能够使用assert通过 C++ 传递的任何这些离子来解决您的问题,但我愿意接受其他人的任何输入,以提示您如何...

数组是连续的。这意味着newMat[x] + wnewMat[x+1],对于 x in 的值0 .. h-1。在您的代码中,这不是现实,因为您是单独分配newMat[x]newMat[x+1]。同样,预计字符串的最大长度newMay[0][y] == newMat[0][y+1] + n在哪里。在使用通用数组排序算法时,这可能是一个问题,因为它们可能依赖于您的数组是连续的。n

最接近解决这个问题的方法似乎是每个维度只分配一次,而不是h为第一个维度和w第二个维度分配时间。这看起来像这样:

char ***getNewMat(size_t w, size_t h, size_t n){
    char ***newMat = new char **[h];
    newMat[0] = new char *[h*w];
    newMat[0][0] = new char[h*w*n];

    for(size_t i = 0; i < h; i++){
        newMat[i] = newMat[0] + i * w;
        for (size_t j = 0; j < w; j++) {
            newMat[i][j] = newMat[0][0] + i * w * n + j * n;
        }
    }

    return newMat;
}

数组连续的一个副作用是,您不能仅通过更改数组中的指针以指向不同的位置来分配C 样式的字符串。指针是从数组表达式转换为不是左值的指针表达式的结果。正如我之前所说,我对 C++ 了解不多,但是在 C 中这意味着以下代码无法编译:

char foo[x][y][z] = { 0 };
foo[a][b] = "hello";

但是,以下代码可以编译:

char *foo[x][y] = { 0 };
foo[a][b] = "hello";

前者可能构成一个 C 风格的字符串数组,但后者不能,因为我们已经介绍了连续性规则,而且它从大多数元素开始,如果它的元素指向NULL,一个不能指向的指针任何东西,更不用说字符串了。您可以执行一些运算符重载魔术来允许前者编译。我也愿意提供任何正确方向的提示,以便为 OP 提供示例,here。

于 2013-05-04T13:46:24.280 回答