首页 > 解决方案 > 函数调用使结构的 const 属性更改其值

问题描述

我正在编写这个简单的库来处理 int 矩阵:

#ifndef MATRIX_H_
#define MATRIX_H_

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct Matrix Matrix;

Matrix* newMatrix(const unsigned int rows, const unsigned int columns);

void setElementAt(Matrix* self, const unsigned int row, const unsigned int column, const int value);

int getElementAt(const Matrix* self, const unsigned int row, const unsigned int column);

int getRowsNo(const Matrix* self);

int getColumnsNo(const Matrix* self);

void initMatrix(Matrix* self, int value);

#endif
#include "Matrix.h"

struct Matrix {

    int* grid;
    const unsigned int rowsNo;
    const unsigned int columnsNo;
};

Matrix* newMatrix(const unsigned int rowsNo, const unsigned int columnsNo) {

    assert(rowsNo > 0 && columnsNo > 0);

    Matrix new = {

        .grid = malloc(rowsNo * columnsNo * sizeof(int)),
        .rowsNo = rowsNo,
        .columnsNo = columnsNo
    };

    Matrix* self = &new;

    return self;
}

int getRowsNo(const Matrix* self) {

    return self->rowsNo;
}

int getColumnsNo(const Matrix* self) {

    return self->columnsNo;
}

int getElementAt(const Matrix* self, const unsigned int row, const unsigned int column) {

    assert(row < self->rowsNo && column < self->columnsNo);

    return self->grid[row * self->rowsNo + column];
}

void setElementAt(Matrix* self, const unsigned int row, const unsigned int column, const int value) {

    assert(row < self->rowsNo && column < self->columnsNo);

    self->grid[row * self->rowsNo + column] = value;
}

void initMatrix(Matrix* self, int value) {

    for(int row = 0; row < self->rowsNo; row++) {

        for(int column = 0; column < self->columnsNo; column++) {

            setElementAt(self, row, column, value);
        }
    }
}

我遇到的问题是,每次调用getElementAt()setElementAt()调用函数时,struct Matrix 实例的 columnsNo 字段(并且只有那个)都会更改为一个巨大的随机值,尽管它被标记为 const。我在这里看不到哪个问题?

标签: cpointersmatrixstruct

解决方案


newMatrix中,您将返回局部变量的地址new。一旦函数返回selfnew就会超出范围并且self不会指向任何地方。取消引用该指针会调用未定义的行为。您需要使用malloc或相关函数动态分配内存,以使其在newMatrix.

这是标记为 c++,但完全相同的概念适用于 c: 可以在其范围之外访问局部变量的内存吗?

这是解决此问题的一种方法

Matrix* newMatrix(const unsigned int rowsNo, const unsigned int columnsNo) {

    assert(rowsNo > 0 && columnsNo > 0);

    Matrix* new = malloc(sizeof *new);
    if (new != NULL)
    {
      new->grid = malloc(rowsNo * columnsNo * sizeof(int));
      if (new->grid == NULL) { /* handle error */ }
      new->rowsNo = rowsNo;
      new->columnsNo = columnsNo;
    }

    return new;
    // on return, the caller should check `newMatrix` returned a valid pointer.
}

请注意, 和 的分配new->rowsNo不会new->columnsNo像上面显示的那样工作,因为它们是const. 分配这些的一种方法是使用memcpy,在此处的最佳答案中可以看到:如何在堆上初始化结构的 const 成员


推荐阅读