#c #arrays #pointers #malloc
#c #массивы #указатели #malloc
Вопрос:
Моя проблема довольно проста, я хочу выделить память для 2d-массива в c, заполнить ее значением -1, затем освободить ее и выйти из программы. Мой код продолжает сбоить, и я не знаю, что я делаю не так… Это то, что я получил:
int main(){
int i,j;
char str1[]="xxxabxcxxxaabbcc";
char str2[]="abc";
int len1=strlen(str1);
int len2=strlen(str2);
printf("%d %d",len1,len2);
//allocate 2d_array
int **H_table = (int**)malloc((len1 1)*sizeof(int));
for (i=0; i<len1 1; i ){
H_table[i] = (int*)malloc((len2 1)*sizeof(int));
}
//fill and print 2d array
for(i=0;i<len1 1;i ){
for(j=0;j<len2 1;j ){
printf("i:%d j:%d",i,j);
H_table[i][j]=-1;
printf(" value:%dn",H_table[i][j]);
}
}
// free 2d array
for(i=0;i<len1;i ){
free(H_table[i]);
}
free(H_table);
return 0;
}
Итак, что происходит, так это то, что я хочу выделить массив, который содержит на 1 дополнительную строку и 1 дополнительный столбец больше, чем 2 строки, если поместить их вертикально по сравнению друг с другом.
И это то, чего я ожидал (элементы в скобках, очевидно, не являются частью таблицы, я поместил их туда для сравнения):
(x x x a b x c x x x a a b b c c)
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
a)1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
b)1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
c)1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Проблема в том, что код завершает работу при заполнении таблицы, и он всегда завершает работу при i = 9 и j = 3 для этих конкретных строк. Странная часть заключается в том, что если вы поменяете местами 2 строки (поместите «abc» в str1), то код проходит стадию заполнения и завершается сбоем при попытке освободить массив.
Извините за любые грамматические ошибки или ошибки stackoverflow, я здесь вроде как новичок: P
Приветствуется любая идея 🙂 заранее спасибо
Комментарии:
1. Вот совет: лучший способ написать malloc — это:
SomeType* some_variable = malloc(n * sizeof *some_variable);
. Например:int** H_table = malloc((len1 1) * sizeof *H_table);
илиH_table[i] = malloc((len2 1) * sizeof * H_table[i]);
. В C нет необходимости явно указывать возвращаемое значение malloc. Использованиеsizeof *variable
вместоsizeof(whatever you think the type should be)
int*
избавляет вас от необходимости думать о том, каким должен быть тип 🙂 и его не нужно менять, если вы позже измените тип переменной, например, с, наlong*
2. @rici и Mike Hatzak, ошибки представляют собой своего рода опечатку, полезен ли этот вопрос для других людей и нужно ли его оставлять, или лучше его удалить?
3. @rici если ты хочешь, чтобы я удалил свой ответ, а ты вставил свой? ^^ Когда я отвечал, я вижу, что xing сделал свое первое замечание параллельно
4. @rici хорошо, я удаляю его
5. Большое спасибо всем за ответы, похоже, проблема действительно была своего рода опечаткой, но то, что предложил xing, заставило ее работать (int-> int*). итак, да, как сказал rici, я изменил все в своем коде в соответствии с тем, что он сказал, просто для уверенности. Если вы хотите удалить поток, я не возражаю, но это может сэкономить людям некоторое время и разочарование, потому что ошибки, подобные этим, заставляют неопытных людей биться головой о стену: P еще раз спасибо
Ответ №1:
Как указывали многие люди, вы выделяете H_table
место для len1 1
целых чисел, но на самом деле предполагается, что это массив len1 1
указателей (на целые числа). Поскольку указатели больше целых чисел (во всяком случае, в вашей системе), вы в конечном итоге получаете неопределенное поведение из-за переполнения буфера.
Вот подсказка. Избегайте этой проблемы и множества других подобных проблем, всегда используя следующую модель для malloc
:
some_variable = malloc(n * sizeof *some_variable);
Например:
int** H_table = malloc((len1 1) * sizeof *H_table);
for (int i = 0; i <= len1; i)
H_table[i] = malloc((len2 1) * sizeof *H_table[i]);
То есть пусть компилятор определит правильный тип для переменной (или lvalue). Компилятор менее подвержен опечаткам, чем вы, и, если не указывать тип явно, вам будет намного проще позже решить, что H_table
должно было быть long
или short
или unsigned
.
По той же причине не приводите явно возвращаемое значение malloc
. C автоматически приводит void*
к целевому типу и не выдает ошибку, если вы вручную приводите к неправильному типу. Так что просто позвольте компилятору сделать это; это меньше ввода, безопаснее и более перспективно.
Обратите внимание, что если вы используете выражение с sizeof
, компилятор не вычисляет выражение [Примечание 1]. Он просто определяет тип и заменяет его выражением. Так что не беспокойтесь о дополнительной оценке: ее нет. Вот почему также можно использовать эту модель с объявлениями, даже если some_variable
она еще не имеет значения при malloc
выполнении.
Примечания:
- Существует одно обстоятельство, при котором компилятор может вычислить
ex
вsizeof ex
: ifex
является массивом переменной длины. Однако в этом случаеex
всегда является указателем, поэтому этот случай не может применяться.
Ответ №2:
Как упоминал @xing в своем комментарии, H_table
является указателем на указатель на целое число. итак, вам нужно изменить int
на int*
в первом malloc
. здесь:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
int i,j;
char str1[]="xxxabxcxxxaabbcc";
char str2[]="abc";
int len1=strlen(str1);
int len2=strlen(str2);
printf("%d %d",len1,len2);
//allocate 2d_array
int **H_table = (int**)malloc((len1 1)*sizeof(int*));
for (i=0; i<len1 1; i ){
H_table[i] = (int*)malloc((len2 1)*sizeof(int));
}
//fill and print 2d array
for(i=0;i<len1 1;i ){
for(j=0;j<len2 1;j ){
printf("i:%d j:%d",i,j);
H_table[i][j]=-1;
printf(" value:%dn",H_table[i][j]);
}
}
// free 2d array
for(i=0;i<len1;i ){
free(H_table[i]);
}
free(H_table);
return 0;
}