#c #exception #multidimensional-array #struct #malloc
#c #исключение #многомерный массив #структура #malloc
Вопрос:
Проблема
У меня есть пользовательская структура для 2D-матриц. Я использую эту структуру внутри функции для инициализации 2D-матрицы, где каждому значению элемента присваивается значение 0. У меня также есть другая функция для печати матрицы на терминал (в целях отладки).
Когда я пишу структуру и функции внутри main.c
, они работают. Проблема в том, что когда я помещаю их в отдельный файл и вызываю их из этого файла, я получаю ошибку времени выполнения: Exception thrown: write access violation
.
В моей программе у меня есть 3 файла: main.c
, my_lib.h
, my_lib.c
. Структура хранится внутри my_lib.h
, а функция находится внутри my_lib.c
. Внутри main.h
Я использую Windows 10 и кодирую в Visual Studio 2017 версии 15.9.10
Вывод
Программа компилируется, но выдает ошибку времени выполнения Exception thrown: write access violation
Редактировать:
Что ж, похоже, это была моя собственная ошибка в том, что это происходило.
На самом деле, я пытался запустить этот код на своем рабочем компьютере. Я написал исходный код на своем персональном компьютере, где работала версия main.c
, my_lib.h
amp; my_lib.c
. Затем я скопировал папку, над которой работал, и попытался продолжить на своем рабочем компьютере. Оба моих компьютера работают под управлением ОС Windows 10, и оба имеют одинаковую версию VS 2017.
На моем персональном компьютере обозреватель решений был похож:
Но на моем рабочем компьютере решение открылось как:
Все, включая иерархию папок, одинаковы на обоих компьютерах. Похоже, копирование папки проекта — не очень хорошая идея.
Когда я создал новый проект C на своем рабочем компьютере и добавил my_lib.c
и my_lib.h
вручную, все заработало.
Но мне все еще любопытно, почему я получал ошибку исключения… И как я могу исправить эту проблему копирования без создания нового проекта в VS?
Код
Просто main.c ( работает)
main.c
#include <stdio.h>
typedef struct Matrix {
int rows; // number of rows
int cols; // number of columns
double** data; // a pointer to an array of n_rows pointers to rows
}Matrix;
Matrix* make_matrix(int n_rows, int n_cols);
void print_matrix(Matrix* m);
int main() {
Matrix* m1 = make_matrix(2, 5);
print_matrix(m1);
return 0;
}
// CREATE A MATRIX WITH N_ROWS AND N_COLUMNS AND INITIALIZE EACH VALUE AS 0
Matrix* make_matrix(int n_rows, int n_cols) {
Matrix* matrix = malloc(sizeof(Matrix));
matrix->rows = n_rows;
matrix->cols = n_cols;
double** data = malloc(sizeof(double*) * n_rows);
for (int x = 0; x < n_rows; x ) {
data[x] = calloc(n_cols, sizeof(double));
}
matrix->data = data;
return matrix;
}
// PRINT GIVEN MATRIX TO COMMAND LINE
void print_matrix(Matrix* m) {
for (int x = 0; x < m->rows; x ) {
for (int y = 0; y < m->cols; y ) {
printf("%f", m->data[x][y]);
printf("|");
}
printf("n");
}
}
main.c amp; function в отдельных файлах (выдает исключение)
main.c
#include "my_lib.h"
int main(){
// Create a 2 by 5 matrix amp; then print it to terminal
Matrix* m1 = make_matrix(2, 5);
print_matrix(m1);
return 0;
}
my_lib.h
#pragma once
// Our custom 2D matrix struct
typedef struct Matrix {
int rows; // number of rows
int cols; // number of columns
double** data; // a pointer to an array of n_rows pointers to rows
}Matrix;
Matrix* make_matrix(int n_rows, int n_cols);
void print_matrix(Matrix* m);
my_lib.c
#include "my_lib.h"
#include <stdio.h>
// CREATE A MATRIX WITH N_ROWS AND N_COLUMNS AND INITIALIZE EACH VALUE AS 0
Matrix* make_matrix(int n_rows, int n_cols) {
Matrix* matrix = malloc(sizeof(Matrix));
matrix->rows = n_rows;
matrix->cols = n_cols;
double** data = malloc(sizeof(double*) * n_rows);
for (int x = 0; x < n_rows; x ) {
data[x] = calloc(n_cols, sizeof(double));
}
matrix->data = data;
return matrix;
}
// PRINT GIVEN MATRIX TO COMMAND LINE
void print_matrix(Matrix* m) {
for (int x = 0; x < m->rows; x ) {
for (int y = 0; y < m->cols; y ) {
printf("%f", m->data[x][y]);
printf("|");
}
printf("n");
}
}
Комментарии:
1. @xing все они находятся в одной папке
2. Не имеет значения, что все они находятся в одной папке. В тот момент, когда main () вызывает make_matrix(), он еще не знает определения make_matrix. Что произойдет, если вы добавите следующую строку в my_lib.h? Matrix* make_matrix(int n_rows, int n_cols);
3. Для верности вам также следует включить
<stdlib.h>
, чтобы получить правильные прототипыm/calloc
.4. Если вместо этого вы используете стандартный компилятор C, это даже не будет компилироваться. Но, эй, прошло всего 20 лет с тех пор, как был выпущен C99, возможно, нам следует дать MS больше времени для адаптации.
5. @OguzCanbek ты забыл
#include <stdlib.h>
. Вы не получали никаких предупреждений компилятора?
Ответ №1:
Причина, по которой вы получаете сбой, вообще не связана с тем фактом, что у вас есть один или два файла .c в вашем проекте, но это потому, что вы забыли включить <stdlib.h>
в my_lib.c
.
Это вызывает следующие предупреждения:
my_lib.c(8) : предупреждение C4013: ‘malloc’ не определено; предполагается, что extern возвращает int
my_lib.c(13): предупреждение C4013: ‘calloc’ не определено; предполагается, что extern возвращает int
my_lib.c(13): предупреждение C4047: ‘=’: ‘double *’ отличается по уровням косвенности от ‘int’
my_lib.c(8): предупреждение C4047: ‘ инициализация ‘: ‘Matrix *’ отличается по уровням косвенности от ‘int’
my_lib.c(11): предупреждение C4047: ‘инициализация’: ‘double **’ отличается по уровням косвенности от ‘int’
Вам это сойдет с рук при 32-разрядной сборке, потому что размер int
совпадает с размером указателя.
С другой стороны, если вы создаете свою программу как 64-разрядную, предупреждения становятся действительно актуальными, потому что теперь указатели имеют ширину 64 бита, но поскольку компилятор предполагает, что malloc
etc. возвращает int
s (32-разрядные значения), все запутывается.
На самом деле эти предупреждения следует рассматривать как ошибки.
Здесь вы решаете, хотите ли вы 32-или 64-разрядную сборку:
Добавьте #include <stdlib.h>
здесь в my_lib.c
:
#include "my_lib.h"
#include <stdlib.h> // <<<<<<<<<<<<<
#include <stdio.h>
// CREATE A MATRIX WITH N_ROWS AND N_COLUMNS AND INITIALIZE EACH VALUE AS 0
Matrix* make_matrix(int n_rows, int n_cols) {
Matrix* matrix = malloc(sizeof(Matrix));
...
Комментарии:
1. Спасибо за ваш ответ и за подробное объяснение 32-разрядных и 64-разрядных программ 🙂 У меня также есть еще один вопрос новичка: должен ли я также включить
<stdlib.h>
в свойmain.c
или, поскольку я добавил его вmy_lib.c
, это не обязательно?2. @OguzCanbek нет, в этом нет необходимости, если только вы не используете одну из функций, объявленных в
stdlib.h
вmain.c
, чего пока нет.