2017-01-14 3 views
1

почему эта ошибка (рисунок 1) произошла, когда я хочу ввести 2d-массив в функцию?несовместимые типы указателей, передающие int [5] [5] параметру типа int **

enter image description here

#include <stdio.h> 
#include <stdlib.h> 
void pr(int** a){ 
    printf("%d", a[0][0]); 
} 

int main(){ 
    int a[5][5]={{1,4,7,11,15},{2,5,8,12,19},{3,6,9,16,22},{10,13,14,17,24},{18,21,23,26,30}}; 
    pr(a); 
} 
+2

Массивы и указатели не совпадают, а указатель на указатели - это не то же самое, что 2D-массив. Вы должны использовать 'void pr (int a [] [5])' или подобное. –

+0

Что делать, если функция pr не может быть изменена? – user7341005

+4

Тогда вам понадобится другая структура массива в 'main()': 'int * a [] = {(int []) {1, 4, 7, 11, 15}, (int []) {2, 5, 8, 12, 19}, (int []) {3, 6, 9, 16, 22}, (int []) {10, 13, 14, 17, 24}, (int []) {18, 21 , 23, 26, 30}}; '- не скомпилирован, поэтому у меня может быть ошибка. Я использую сложные литераторы C99. Это дает вам массив указателей на 'int', но каждый указатель находится в начале массива' int'. –

ответ

5

Основная проблема заключается в том, что массивы и указатели не совпадают (хотя они тесно связаны), а 2D-массив не является массивом указателей.

Этот код показывает три способа устранить проблему. Массив a0 - ваш массив, переименованный и переформатированный; массив a представляет собой массив указателей, и каждый указатель представляет собой указатель на массив из 5 int через «составной литерал», добавленный в C99. Я обновил функцию печати, чтобы напечатать все 25 элементов массива, которые ей переданы, и создал две новые функции печати с различными интерфейсами, которые также распечатывают весь массив, переданный им. Я предполагаю, что массив квадратный; прямоугольная (неквадратная) матрица может быть легко обработана, особенно по варианту на pr1(), например pr2(int n, int m, int a[n][m]), который почти идентичен pr1(), но для проверки j требуется только одна настройка для m вместо n.

#include <stdio.h> 

static void pr0(int a[][5]); 
static void pr1(int n, int a[n][n]); 

static void pr(int **a) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     for (int j = 0; j < 5; j++) 
      printf("%3d", a[i][j]); 
     putchar('\n'); 
    } 
    putchar('\n'); 
} 

int main(void) 
{ 
    int a0[5][5] = 
    { 
     { 1, 4, 7, 11, 15 }, 
     { 2, 5, 8, 12, 19 }, 
     { 3, 6, 9, 16, 22 }, 
     { 10, 13, 14, 17, 24 }, 
     { 18, 21, 23, 26, 30 }, 
    }; 
    int *a[] = 
    { 
     (int[]){ 1, 4, 7, 11, 15 }, 
     (int[]){ 2, 5, 8, 12, 19 }, 
     (int[]){ 3, 6, 9, 16, 22 }, 
     (int[]){ 10, 13, 14, 17, 24 }, 
     (int[]){ 18, 21, 23, 26, 30 }, 
    }; 

    pr(a); 
    pr0(a0); 
    pr1(5, a0); 

    return 0; 
} 

static void pr0(int a[][5]) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     for (int j = 0; j < 5; j++) 
      printf("%3d", a[i][j]); 
     putchar('\n'); 
    } 
    putchar('\n'); 
} 

static void pr1(int n, int a[n][n]) 
{ 
    for (int i = 0; i < n; i++) 
    { 
     for (int j = 0; j < n; j++) 
      printf("%3d", a[i][j]); 
     putchar('\n'); 
    } 
    putchar('\n'); 
} 

Образец выход удивительно однородным:

1 4 7 11 15 
    2 5 8 12 19 
    3 6 9 16 22 
10 13 14 17 24 
18 21 23 26 30 

    1 4 7 11 15 
    2 5 8 12 19 
    3 6 9 16 22 
10 13 14 17 24 
18 21 23 26 30 

    1 4 7 11 15 
    2 5 8 12 19 
    3 6 9 16 22 
10 13 14 17 24 
18 21 23 26 30 

Три блоки являются одинаковыми.Учитывая выбор, я использовал бы технику в pr1(), используя VLAs (массивы переменной длины) в интерфейсе. Если вы должны придерживаться аргумента int **, вы должны придерживаться массива a или чего-то подобного. Конечно, есть другие способы создать это. Например:

int *a[] = { a0[0], a0[1], a0[2], a0[3], a0[4] }; 
4

Массивы и указатели не могут быть использованы взаимозаменяемо в всех возможных случаев использования, и вы просто случайно наткнуться на одну из них. Время от времени массив int может быть неявно преобразован в указатель, а порой его, должно быть, быть не должно.

В вашем случае неявное (или явно) преобразование a в (int **) не будет работать, просто потому, что a указывает на первый элемент в вашем 2d-массиве, если он рассматривается как указатель. Преобразование a в int ** приведет к тому, что pr потеряет информацию о a, являющемся массивом. Следовательно, обработка его как типичного (int **) в pr и попытка его разыменования дважды приведет к тому, что первый элемент в a (a[0][0] = 1) будет обрабатываться как адрес, и значение в этом адресе будет просмотрено, что, я считаю, не желаемое поведение pr().

В идеале вы должны объявить pr таким образом, чтобы в качестве параметра принимался 2D-массив, а не int **. Ниже приводится декларация pr с указанным исправлением.

void pr(int a[][5]){ 
    printf("%d", a[0][0]); 
} 

Теперь, когда вы упоминаете в комментариях к вопросу о том, что определение pr не может быть изменено. Чтобы не изменять pr(), вам нужно будет изменить структуру данных, которую вы имеете в main, на что-то похожее на приведенное ниже.

int main(){ 
    int a0[5]={1,4,7,11,15}; 
    int a1[5]={2,5,8,12,19}; 
    int a2[5]={3,6,9,16,22}; 
    int a3[5]={10,13,14,17,24}; 
    int a4[5]={18,21,23,26,30}; 
    int *a[5] = {a0, a1, a2, a3, a4}; 
    pr(a); 
} 

Обратите внимание, что приведенный выше пример не является наиболее синтаксически сжатым способом достижения вашей цели. Кроме того, отметьте here, чтобы увидеть это использование на работе.

Смежные вопросы