c - 函数调用使结构的 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。我在这里看不到哪个问题?
解决方案
在newMatrix
中,您将返回局部变量的地址new
。一旦函数返回self
,new
就会超出范围并且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 成员
推荐阅读
- c++ - 可以通过复制来初始化一组吗?
- node.js - SSL 上的 Nginx 代理传递不考虑监听 URL
- python - 为什么我不能在 qt 设计器中向 textBrowser 添加列表?
- c - C 中的电子表格应用程序
- swift - 为什么在复制实例变量时出现“尝试注销未知的 __weak 变量”?
- ios - 如何从 String Swift 中删除 '\u{ef}' 字符
- java - Selenium(JAVA) Grid 仅在 Windows 中启动 10 个并行浏览器
- javascript - 如何使用 javascript 编写 firebase 参考查询?
- go - 为 vscode 项目/终端设置 $GOPATH
- java - 不建议在没有服务器身份验证的情况下建立 SSL 连接