Динамически выделяющий 2d-массив при ошибке c

#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 выполнении.


Примечания:

  1. Существует одно обстоятельство, при котором компилятор может вычислить ex в sizeof ex : if ex является массивом переменной длины. Однако в этом случае 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;
}