замена строк массива и печать, c - PullRequest
1 голос
/ 25 сентября 2011

это то, что беспокоило меня последние два часа. Я пытаюсь поменять две строки в двухмерном массиве. Это не проблема, но я хочу сделать это с помощью функции подкачки, которая получает указатели. Вот что у меня есть:

#include <stdio.h>
#include <stdlib.h>

void swapRows(int **a, char **b)
{
    int *temp = *a;
    *a = *b; // WARNING #1
    *b = temp; // WARNING #1

}

void print(int a[][2],int rows,int cols)
{
    int i,j;
    for (i=0; i<rows; i++)
    {
        for (j=0; j<rows; j++)
        {
            printf("%d ",a[i][j]);
        }
        printf("\n");
    }
}

int main(void)
{
    int matrix[2][2] = {{1,2},{3,4}};
    print(matrix,2,2);
    swapRows(&matrix[0],&matrix[1]); //WARNING #2
    print(matrix,2,2);
    return EXIT_SUCCESS;
}

Итак, вот мои вопросы:

1) Функции подкачки меняются только между первыми элементами в каждом массиве, что имеет смысл. Как мне заставить его поменять местами другие элементы? Должен ли я перебирать всю строку?

2) При объявлении печати это работало только если я установил a[][]2. До этого я пытался написать int **arr, но у меня была ошибка сегментации. Это почему? Кроме того, почему я должен указать количество столбцов в аргументе массива? Для этого у меня есть строки и столбцы, почему компилятор заставляет меня это делать?

3) наконец, используя эту версию print(), я получаю предупреждение от компилятора passing argument 2 of ‘swapRows’ from incompatible pointer type (предупреждение # 2 в коде) и получаю другое предупреждение (# 1): assignment from incompatible pointer type в swapRows(). Это почему? Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 25 сентября 2011

Источник вашей путаницы:

Тип

int m1[2][2]; // a *single* block of memory of size 2*2*sizeof(int)
              //
              // this is a *real* 2d-array

равен , а не такой же, как у

int **m2;  // a pointer of size sizeof(int*) almost certainly the 
           // equal to sizeof(void*)
           //
           // This could be made to point at at least two logically 
           // distinct blocks of memory and *act* like a 2d-array

Да, m2 (указатель на указатель) можно разыменовать , используя [][], но m1 (фактический двумерный массив) не может быть разыменованным с **.

Это означает, что ваш вызов поменять строки - ужасная ошибка.Посмотрите, почему ...

  • matrix[0] - это первый подмассив (и int[2], содержащий {1,2}), его адрес является пустой операцией, которая получает адрес матрицы [0] [0], это место в памяти, содержащее целочисленное представление 1 (то есть это указатель на int).
  • Аналогичный аргумент применяется к &matrix[1], оно указывает на памятьсодержащий 2.

Вы вызываете swapRows, который думает, что эти аргументы являются указателями на указатели на int (а это не так, поэтому ваш компилятор выдает предупреждение).Однако он будет работать, потому что указатель на int имеет тот же размер, что и указатель на указатель на int (это не гарантируется строго, но обычно вам это сходит с рук).Когда он запускается, он заменяет содержимое размером с точку-на-интервал a на содержимое размера указателя на-int b.Если случится так, что sizeof(int) == sizeof(int*) (что не редкость), это будет равносильно замене matix[0][0] на matrix[1][0].

Это не то, что вы хотели.

Что вы можете с этим поделать?

  • Объявите matrix в качестве указателя на указатель и выделите память, как в рваном массиве, затем используйте существующий своп
  • Объявите matrixв качестве массива указателей и выделите память для строк, затем используйте существующий своп
  • Сохраните существующее объявление matrix и перезапишите своп для замены каждого значения.
  • Сохранитесуществующее объявление matrix, но также предоставьте массив указателей аксессора, используйте существующий своп на аксессоре и всегда используйте аксессор (единственное возможное преимущество этого по сравнению с первыми двумя опциями - то, что все находится в стеке).
  • Использование хака "строка как структура".

Структура "строка как структура"

Учтите это

typedef struct {
   int r[2];
} row_t;
row_t m3[2];

m3 - это массив структур, каждая из которых является массивом int s.Доступ - это немного сомнительно: m3[i].r[j], , но вы можете сделать

row_t temp = m3[n];
m3[n] = m3[m];
m3[m] = temp;

, чтобы поменять строки.

0 голосов
/ 25 сентября 2011

Массивы и указатели - разные вещи, хотя во многих случаях C заставляет их вести себя одинаково.Вы также случайно использовали char вместо int для второго параметра.Ваша функция swapRows должна быть объявлена ​​так:

void swapRows(int (*a)[2], int (*b)[2])

Вам нужно поменять местами (* a) [0] с (* b) [0] и (* a) [1] с (* b) [1].

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

Это просто ограничение C, которое должно иметь массивыразмер, который известен во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...