Проверить была ли произведена запись в структуру
#include <stdio.h>
#include <stdlib.h>
#define NOT_VALID_MATRIX 1
#define OK 0
typedef struct matrix_struct {
double** matrix;
int rows;
int columns;
} matrix_t;
int validMatrix(matrix_t *matrix) {
int returnValue = 0;
if ((*matrix).columns > 0 && (*matrix).rows > 0) {
returnValue = 1;
}
return returnValue;
}
int create_matrix(int rows, int columns, matrix_t *result) {
int returnValue = OK;
if (rows > 0 && columns > 0) {
(*result).rows = rows;
(*result).columns = columns;
(*result).matrix = malloc(rows * sizeof(double*));
for (int i = 0; i < rows; i++) {
(*result).matrix[i] = malloc(columns * sizeof(double));
}
} else {
returnValue = NOT_VALID_MATRIX;
}
return returnValue;
}
int main() {
matrix_t matrix;
matrix_t matrix2;
create_matrix(2, 2, &matrix);
create_matrix(3, 0, &matrix2);
int result = validMatrix(&matrix);
printf("%d ", result);
result = validMatrix(&matrix2);
printf("%d ", result);
return 0;
}
Как проверить, была ли выделена память/произведена запись под структуру? Что ни поставлю в условие validMatrix, это условие всегда выполняется.
Поставил (*matrix).matrix != NULL, вроде как сработало. Но сработало только в мейне, в тестах с библиотекой <check.h> все равно проходит условие.
Вот код с тестом:
#include <stdio.h>
#include <stdlib.h>
#include <check.h>
#define NOT_VALID_MATRIX 1
#define OK 0
typedef struct matrix_struct {
double** matrix;
int rows;
int columns;
} matrix_t;
int validMatrix(matrix_t *matrix) {
int returnValue = 0;
if ((*matrix).matrix != NULL) {
returnValue = 1;
}
return returnValue;
}
int create_matrix(int rows, int columns, matrix_t *result) {
int returnValue = OK;
if (rows > 0 && columns > 0) {
(*result).rows = rows;
(*result).columns = columns;
(*result).matrix = malloc(rows * sizeof(double*));
for (int i = 0; i < rows; i++) {
(*result).matrix[i] = malloc(columns * sizeof(double));
}
} else {
returnValue = NOT_VALID_MATRIX;
}
return returnValue;
}
START_TEST(valid) {
matrix_t matrix;
matrix_t matrix2;
matrix_t matrix3;
create_matrix(2, 2, &matrix);
create_matrix(3, 0, &matrix2);
int counter = 1;
int result = validMatrix(&matrix2);
ck_assert_int_eq(result, 10);
}
END_TEST
int main() {
Suite *s1 = suite_create("s21_matrix: ");
TCase *tc1_1 = tcase_create("s21_matrix: ");
SRunner *sr = srunner_create(s1);
int result;
suite_add_tcase(s1, tc1_1);
tcase_add_test(tc1_1, valid);
srunner_run_all(sr, CK_ENV);
result = srunner_ntests_failed(sr);
srunner_free(sr);
return result == 0 ? 0 : 1;
}
Ответы (1 шт):
malloc() если выделил память возвращает указатель, если не выделил (не важно по каким причинам) - возвращает 0 (nullptr) - On success, returns the pointer to the beginning of newly allocated memory. On failure, returns a null pointer.
Проблема будет в другом - если память под структуру не выделена, то при вызове validMatrix(matrix_t *matrix) будет обращение по нулевому указателю, что является UB. Либо если вы вызовите validMatrix() до вызова create_matrix() будет сравнение с "мусорными" значениями.
int validMatrix(matrix_t *matrix) // если память не выделена, то *matrix == nullptr либо мусорному значению
{
if ( (*matrix).columns > 0 && // чтение за пределами своей памяти
(*matrix).rows > 0) // чтение за пределами своей памяти
returnValue = 1;
}
int validMatrix(matrix_t *matrix)
{
// если create_matrix() не вызывалась, значит здесь будет не 0
// если create_matrix() вызывалась, но выделение памяти сбойнуло не на первом выделении, значит здесь будет не 0
if ((*matrix).matrix != NULL)
returnValue = 1;
}
Правильность выделения памяти нужно проверять в момент выделения. И до выделения обнулить указатели. А в случае неуспешного выделения - выполнить действия для освобождения ранее выделенной памяти.
int create_matrix(int rows, int columns, matrix_t *result)
{
// если объекты matrix_t тоже выделяются динамически, то нужно проверить и *result
if(!result)
return NOT_VALID_MATRIX;
// вот тут нужно обнулить все поля matrix_t !!!!!
// чтобы даже после выхода с негативным результатом поля были обнулены
if (rows <= 0 or columns <= 0)
return NOT_VALID_MATRIX;
int returnValue = OK;
// присваивать значения rows и columns лучше после того, как операции выделения памяти завершились успешно - т.е. в конце функции
// (*result).rows = rows;
// (*result).columns = columns;
(*result).matrix = malloc(rows * sizeof(double*)); // здесь проверить результат выделения
for (int i = 0; i < rows; i++) // обнулить все matrix[i]
(*result).matrix[i] = nullptr;
for (int i = 0; i < rows; i++)
{
(*result).matrix[i] = malloc(columns * sizeof(double));
if((*result).matrix[i] == nullptr ) // здесь проверить результат выделения
{
returnValue = NOT_VALID_MATRIX;
break;
}
}
// в случае неуспешного выделения - выполнить действия для освобождения ранее выделенной памяти
if(returnValue == NOT_VALID_MATRIX)
{} // освободить ранее выделенную память, обнулить все данные или другие действия и выход с отрицательным результатом
// если всё - ОК
(*result).rows = rows;
(*result).columns = columns;
return ОК;
}
В общем обязательное условие - вызов create_matrix() сразу после создания матрицы, до вызовов любых других функций. Для вас create_matrix() - аналог конструктора в C++.
А в create_matrix() необходимо занулять все поля matrix_t. Это дает гарантии, что:
- если все нули, значит
create_matrix()отработала с ошибками (память не выделилась или матрицу создать невозможно) - если указатель не 0 и rows columns положительные - значит память выделена и всё ОК