2016-11-13 2 views
0

Я запрограммировал функцию, которая может вращать 4 x 4 массива, и теперь я хочу ее вывести ... Но я получаю предупреждения сгустка, но она компилируется и работает, поэтому, я думаю, я только что сделал «незначительные/формальные» ошибки.Указатели, массивы и функции

#include <stdio.h> 

//----------------------------------------------------------------------------- 
/// 
/// This function prints four 4x4 matrix 
/// 
/// @param m1, m2, m3, m4 input matrix you want to print. 
/// 
/// @return 0 
//----------------------------------------------------------------------------- 

void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4]) 
    { 
     for(int i = 0; i < 4; i++) 
     { 
      for(int j = 0; j < 4; j++) 
      { 
       printf("%c ", m1[i][j]); 
      } 
      printf(" "); 
      for(int j = 0; j < 4; j++) 
      { 
       printf("%c ", m2[i][j]); 
      } 
      printf(" "); 
      for(int j = 0; j < 4; j++) 
      { 
       printf("%c ", m3[i][j]); 
      } 
      printf(" "); 
      for(int j = 0; j < 4; j++) 
      { 
       printf("%c ", m4[i][j]); 
      } 
      printf("\n"); 
     } 
     printf("\n"); 
     return 0; 
    } 

//----------------------------------------------------------------------------- 
/// 
/// This function rotates a 4x4 matrix 
/// (and collects tears from overworked students @2am, because wtf is ) 
/// 
/// @param m, the matrix you want to rotate 
/// 
/// @return m_r the rotated matrix 
//----------------------------------------------------------------------------- 

char *rotate_matrix(char m[4][4]) 
{ 
    static char m_r[4][4]; 
    for(int i = 0; i < 4; i++) 
    { 
     for(int j = 0; j < 4; j++) 
     { 
      m_r[i][j] = m[3-j][i]; 
     } 
    } 
    return *m_r; 
} 

int main(void) 
{ 
char matrix_t [4][4] = {{ '-', '-', '-', '-' }, 
         { '-', 'O', '-', '-' }, 
         { 'O', 'O', 'O', '-' }, 
         { '-', '-', '-', '-' } 
         }; 
char matrix_z [4][4] = {{ '-', '-', '-', '-' }, 
         { '-', 'O', 'O', '-' }, 
         { 'O', 'O', '-', '-' }, 
         { '-', '-', '-', '-' } 
         }; 
char matrix_l [4][4] = {{ '-', '-', '-', '-' }, 
         { '-', 'O', '-', '-' }, 
         { '-', 'O', '-', '-' }, 
         { '-', 'O', 'O', '-' } 
         }; 
char matrix_i [4][4] = {{ '-', '-', 'O', '-' }, 
         { '-', '-', 'O', '-' }, 
         { '-', '-', 'O', '-' }, 
         { '-', '-', 'O', '-' } 
         }; 
char (*array)[4][4]; 

    print_matrix(matrix_t, matrix_z, matrix_l, matrix_i); 
    array = rotate_matrix(matrix_t); 
    print_matrix(array, matrix_z, matrix_l, matrix_i); 
    return 0; 
} 

Это те ошибки я получаю:

102:9: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types] 


array = rotate_matrix(matrix_t); 

,

103:16: warning: passing argument 1 of ‘print_matrix’ from incompatible pointer type [-Wincompatible-pointer-types] 


print_matrix(array, matrix_z, matrix_l, matrix_i); 

и

note: expected ‘char (*)[4]’ but argument is of type ‘char (*)[4][4]’ 


void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4]) 

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

ответ

1

Предупреждений являются потому, что они:

char *   // pointer to char   or to first element of char[] 
char (*)[4]  // pointer to char[4]  or to first element of char[][4] 
char (*)[4][4] // pointer to char[4][4] or to first element of char[][4][4] 

различные типы. Указатель не просто обозначает ячейку памяти, но также (через свой тип), как следует интерпретировать эту ячейку памяти.

Один сложный бит - это имя массива (или любое другое выражение, которое оценивается в массиве) распадается на указатель. Например, это совершенно верно:

char abc[4] = "abc"; // abc is an array of four characters 
char a = *abc;   // a is 'a', the first character of abc 

. , , и, наоборот, вы можете использовать нотацию массива на указателе (для выполнения арифметических операций над указателями и немедленно разыменованием результата):

char * abc = "abc";  // abc is a pointer (into static memory) 
char c = abc[2];  // c is 'c', the third character of abc 

Так char * равноценен с char()[], char (*)[4] равноценно с char()[][4] и char (*)[4][4] равноценно с char()[][4][4].

И что отличает extra сложно, так как C не поддерживает передачу массива в качестве параметра функции (хотя, если вы действительно этого хотите, вы можете добиться такого же эффекта, обернув массив в структуру и передав что). Это позволяет вам объявлять параметр функции как имеющий тип массива, но на самом деле это синтаксический сахар для параметра функции с указателем . Таким образом, эти три подписи эквивалентны:

void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4]) 
void *print_matrix(char m1[][4], char m2[][4], char m3[][4], char m4[][4]) 
void *print_matrix(char (*m1)[4], char (*m2)[4], char (*m3)[4], char (*m4)[4]) 

Ваш код работает, потому что ваши различные предупреждения все вроде компенсируют:

  • rotate_matrixдолжен возвращение либо char (*)[4] (указатель на первую строку char[][4]) или char (*)[4][4] (указатель на полный char[4][4]). Вместо этого вы возвращаете char *, и для этого вы разыскиваете желаемый указатель, тем самым получая (после распада матрицы-указателя) указатель на первый элемент первой строки матрицы. Конечно, все эти указатели указывают на одно и то же место в памяти, только с разными типами.
    • Чтобы объявить это с возвратным типом char (*)[4], вы можете написать char (*rotate_matrix(char m[4][4]))[4]. , , но, вероятно, лучше объявить тип row, typedef char row[4], а затем написать row * rotate_matrix(char m[4][4]). В этом случае вы должны вернуть m_r в конец, который распадается на указатель на первую строку m_r.
    • Чтобы объявить его с возвратным типом char (*)[4][4], то же самое, только с дополнительным [4] (и его именем, как matrix, а не row). В этом случае вы должны вернуть &m_r в конце, то есть указатель на весь m_r.
    • Любой из приведенных выше подходов является отличным ИМХО, хотя, конечно, вам нужно будет настроить вызывающие сайты для соответствия. Для остальной части этого ответа, я собираюсь предположить, что мы делаем вторую версию, с возвратным типом char (*)[4][4].
  • array имеет тип char (*)[4][4], что хорошо. Предупреждение о коде в array = rotate_matrix(matrix_t) связано с неправильной декларацией rotate_matrix. Но фактическое значение возвращаемого указателя было уже прекрасным, по крайней мере, на типичных платформах.
    • Это говорит, что если вы собираетесь использовать этот тип для array, то вы, вероятно, следует назвать его array_ptr, так как это указатель к обычному типу массива.
  • Но тогда вы передаете array в качестве аргумента print_matrix, который принимает параметр типа char [4][4], то есть char (*)[4]. Вы не можете преобразовать char (*)[4][4] (указатель на массив из 4 строк по 4 символа) на char (*)[4] (указатель на массив из 4 символов). Чтобы исправить это, вам просто нужно разыскать array, отправив вместо этого *array.

(Примечание: Я не уверен, что все перечисленные выше неявных преобразований фактически гарантировано работать, указатели на различные типы объектов, не все могут быть равноценно на всех платформах и даже на типичных современных платформах. , где они являются все равноценны, вы можете прервали строгие правила наложения спектров, что означает, что ваш компилятор может в конечном итоге выполнении оптимизаций, которые полностью ломают свой код. Но это будет обычно работа.)

+0

Спасибо! Но я никогда не использовал одномерный массив в моем коде ... Есть ли какая-либо формальная ошибка при описании 2-мерных массивов, которые заставляют думать, что я использовал одномерный? Потому что это сводит меня с ума ... –

+0

@ManuelBurgstaller: Да; извините, я упомянул об этом в своем последнем абзаце, но я не сделал большого смысла, потому что я забыл, что это на самом деле * относится к вашей программе. (Я думал об этом как «кстати».) Я отредактирую свой ответ, чтобы быть более ясным. – ruakh

+0

Спасибо, чувак, я попробую обернуть вокруг себя голову после того, как поспать (не ложиться спать на 5 часов позже, как вчера, xD) –

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