#arrays #c #multidimensional-array #realloc
Вопрос:
#include <stdio.h>
#include <stdlib.h>
void Append(int **arr, int *count, int *len, int x, int y){
if (*count >= *len){
*len *= 2;
arr = realloc(arr, *len * sizeof(int*));
for (int i=*count; i< *len; i){
arr[i] = (int *) malloc(sizeof(int) * 2);
}
}
arr[*count][0] = x;
arr[*count][1] = y;
*count;
}
int main(){
int **arr, count, len;
arr = (int **) malloc(sizeof(int *) * 1);
arr[0] = (int *) malloc(sizeof(int) * 2);
count = 0;
len = 1;
for (int i=0; i<100; i){
Append(arr, amp;count, amp;len, i, i);
printf("%d - %d %dn", i, arr[i][0], arr[i][1]);
}
return 0;
}
из
0 - 0 0
1 - 1 1
Segmentation Fault
У меня есть такой код, и я получаю ошибку, как описано выше. Я не мог найти, где возникла проблема. Вы можете помочь?
Когда я изменяю код, как показано ниже, я не получаю никаких ошибок, и код работает правильно. в чем разница между этими двумя?
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int **arr;
int len;
int count;
}ARRAY;
void Append(ARRAY *array, int x, int y){
if (array->count >= array->len){
array->len *= 2;
array->arr = realloc(array->arr, array->len * sizeof(int *));
for (int i=array->count; i< array->len; i){
array->arr[i] = (int *) malloc(sizeof(int) * 2);
}
}
array->arr[array->count][0] = x;
array->arr[array->count][1] = y;
array->count;
}
int main(){
ARRAY coordinate;
coordinate.arr = (int **) malloc(sizeof(int *) * 1);
coordinate.arr[0] = (int *) malloc(sizeof(int) * 2);
coordinate.len = 1;
coordinate.count = 0;
for (int i=0; i<100; i){
Append(amp;coordinate, i, i);
printf("%d - %d %dn", i, coordinate.arr[i][0], coordinate.arr[i][1]);
}
return 0;
}
…………………………………………………………………………….
Комментарии:
1. Когда вы
arr = realloc(arr,...)
находитесь в функции, она не изменяетarr
указательmain
. Таким образом, указатель всегда указывает наmalloc
возвращенную исходную память.2. в исходном коде параметр
arr
представляет собой двойной указатель, но ваши ссылки на то, куда указывает этот параметр, не позволяют разыменовать эти обращения, в результате чего код ссылается на параметр в стеке вызовов, а не на данные вmain()
3. OT: вызов
malloc()
возвращаетvoid*
значение, которое может быть присвоено любому указателю, поэтому не следует приводить возвращаемое значение, так как оно просто загромождает код и подвержено ошибкам.4. ОТ: вызов
realloc()
может завершиться неудачно. Поэтому всегда следует присваивать возвращаемое значение временному указателю, проверять временный указатель на ненулевое значение, а если не равно НУЛЮ, то присваивать временный указатель целевому указателю. В противном случае при сбое вызова целевому указателю будет присвоено значение NULL, что приведет к потере выделенной памяти, что приведет к утечке памяти5. ОТ: при возврате из
main()
, для надежного кода, все эти выделения памяти должны быть переданыfree()
Ответ №1:
realloc()
функция довольно сложна в деталях. Время от времени это работает по-разному. Например, предположим , вы выделили массив, содержащий два int
s, с помощью malloc()
и вызываете realloc()
, чтобы увеличить его размер.
int *arr;
arr = malloc(sizeof(int) * 2);
arr = realloc(arr, sizeof(int) * 5);
Иногда, realloc()
будет только расти в размерах. Но иногда это будет работать так, как вы написали вот так:
int *arr;
arr = malloc(sizeof(int) * 2);
int *new;
new = malloc(sizeof(int) * 5);
memcpy(new, arr, 2); //copy first 2 elements of arr to new
free(arr);
arr = new;
Это означает, что realloc()
иногда значение будет меняться arr
.
int *arr1;
int *arr2;
arr1 = malloc(sizeof(int) * 2);
arr2 = realloc(arr1, sizeof(int) * 5);
if (arr1 == arr2)
printf("not changedn");
else
printf("changedn");
Таким образом, приведенный выше код иногда будет печатать «не изменен», а иногда «изменен» (я не уверен, что один и тот же код будет воспроизводить разные результаты. Что я могу с уверенностью сказать, так это то, что результат будет отличаться в зависимости от нового размера, который вы отправили realloc()
).
Таким образом, причина, по которой ваш первый код генерирует два элемента, заключается в том, что realloc()
значение не меняется arr
при первых нескольких вызовах, а после этого изменилось значение. Но, как отметил пользователь 3629249 в комментарии , realloc()
изменилась локальная переменная arr
, а не arr
от main()
. Затем ваша следующая попытка доступа к пространству памяти, на которое arr
указывает , например arr[i][0]
, должна привести к ошибке сегментации, поскольку пространство памяти, на которое arr
указывает, уже освобождено.
Извините за любые грамматические ошибки. Я не являюсь носителем английского языка.
Ответ №2:
Проблема связана не realloc
с чем-то, а с чем-то очень важным для программирования на языке Си.
В языке C при передаче переменной в функцию это значение переменной, которое передается и сохраняется в новой переменной. Следствием этого является то, что вы не можете изменить значение передаваемой переменной.
Простой пример:
void foo(int x)
{
printf("%dn", x); // Will print 42
x = 5;
printf("%dn", x); // Will print 5
}
void bar()
{
int x = 42;
printf("%dn", x); // Will print 42
foo(x);
printf("%dn", x); // Will still print 42 because foo can't change this x
}
x
in bar
и x
in foo
-это две разные переменные, поэтому изменение x
if foo
не меняет x
in bar
.
Именно в этом и заключается проблема с вашим первым примером кода. Переменная arr
in main
не изменится в результате присвоения arr = realloc(...
.
Чтобы изменить значение arr
in main
внутри функции, вы должны передать указатель на arr
, т. е. Append(amp;arr, ...
Теперь вы программист с тремя звездами.
Снова используя простой пример:
void foo(int* x)
{
printf("%dn", *x); // Will print 42
*x = 5;
printf("%dn", *x); // Will print 5
}
void bar()
{
int x = 42;
printf("%dn", x); // Will print 42
foo(amp;x); // Pass the address of x
printf("%dn", x); // Will print 5 because foo changed this x
}
Теперь foo
можно изменить значение x
in bar
, потому foo
что передается адрес x
.
И это именно то, что вы делаете во втором примере кода, т. Е. вы вносите изменения только в значения, на которые указывает, array
что находится coordinate
внутри main
.