Как извлечь подматрицу 2x2 из большей матрицы

Я очень простой пользователь и мало что знаю о командах, используемых в C, поэтому, пожалуйста, потерпите меня... Я не могу использовать очень сложные коды. У меня есть некоторые знания в библиотеке stdio.h и ctype.h, но это все. У меня есть матрица в текстовом файле, и я хочу загрузить матрицу на основе моего ввода количества строк и столбцов.

Например, у меня в файле есть матрица 5 на 5. Я хочу извлечь конкретную подматрицу 2 на 2, как я могу это сделать?

Я создал вложенный цикл, используя:

FILE *sample
sample=fopen("randomfile.txt","r"); 
for(i=0;i<rows;i++){
  for(j=0;j<cols;j++){
     fscanf(sample,"%f",&matrix[i][j]);
   }
 fscanf(sample,"\n",&matrix[i][j]);
}
fclose(sample);

К сожалению, код не работает. Если у меня есть эта матрица:

5.00 4.00 5.00 6.00 
5.00 4.00 3.00 25.00 
5.00 3.00 4.00 23.00 
5.00 2.00 352.00 6.00

И вводя 3 для строки и 3 для столбца, я получаю:

5.00 4.00 5.00
6.00 5.00 4.00
3.00 25.00 5.00

Мало того, что это не подматрица 2 на 2, но даже если бы я хотел первые 3 строки и первые 3 столбца, это не печатало ее правильно....

Мне нужно начать со строки 3 и столбца 3, затем взять подматрицу 2 на 2!

Я должен был закончить с:

4.00 23.00 
352.00 6.00

Я слышал, что для этого можно использовать fgets и sscanf. Вот мой пробный код:

fgets(garbage,1,fin);
sscanf(garbage,"\n");

Но и это не работает :(

Что я делаю неправильно ?

Пожалуйста помоги. Спасибо !


person NLed    schedule 09.05.2010    source источник
comment
Почему вы удалили этот вопрос в последний раз, когда вы разместили его? stackoverflow.com/ questions/2796071/ Если вы удалите свои вопросы, это снизит вероятность того, что люди захотят тратить время на то, чтобы дать хорошие ответы.   -  person Mark Byers    schedule 09.05.2010
comment
У меня была ошибка в вопросе, я хотел подматрицу 2x2 (ошибка с моей стороны)   -  person NLed    schedule 09.05.2010
comment
В будущем, если в вашем вопросе будет ошибка, вам лучше просто исправить ее, а не создавать совершенно новый пост.   -  person dbyrne    schedule 09.05.2010
comment
Понятно, спасибо за совет.   -  person NLed    schedule 09.05.2010


Ответы (3)


Итак, вы хотите прочитать подматрицу размера n x m, начиная с позиций x, y в большая матрица размера p x q. Вам нужны две вещи:

  1. (убедитесь, что x + n ‹= p и y + m ‹= во)
  2. перейдите к первому элементу матрицы, которую вы хотите прочитать. Для этого необходимо сначала пропустить первые строки y - 1.
  3. пропустите x - 1 элементов из следующей строки, затем прочитайте n элементов в свою подматрицу. Повторить m раз.

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

FILE *sample = fopen("randomfile.txt", "r");
// skip the first y-1 rows
for (i = 0; i < y - 1; i++) {
  fscanf(sample, "%*[^\n]\n", &matrix[i][j]);
}
for (i = 0; i < m; i++) {
  // skip the first x-1 numbers
  for (j = 0; j < x - 1; j++) {
     fscanf(sample, "%*f");
  }
  // read n numbers
  for (j = 0; j < n; j++) {
     fscanf(sample, "%f", &matrix[i][j]);
  }
  if (x + n < p) {
    // consume the rest of the line
    fscanf(sample, "%*[^\n]\n");
  }
}
fclose(sample);

Обновление: читать подматрицу из массива стало еще проще, просто требуется немного больше вычислений. Суть в том, что матрица размера p x q может храниться в непрерывном массиве размером p x q таким образом, что матрица [i,j] может быть прочитана из массива [i*(j-1)+j] (приблизительно - могут быть ошибки по одному, и я никогда не уверен, какой столбец, а какой - ряд, но, надеюсь, вы поняли идею :-)

Таким образом, код будет примерно таким

for (i = 0; i < m; i++) {
  for (j = 0; j < n; j++) {
     submatrix[i][j] = array[(y + i) * p + x + j];
  }
}
person Péter Török    schedule 09.05.2010
comment
Спасибо за ответ. А если матрица 50х25. Буду ли я использовать строку или столбец для сравнения? n=2 , х+2‹50 или х+2‹25 ? - person NLed; 09.05.2010
comment
Большое спасибо, мой код получился чем-то похожим, но у меня была ошибка, что я забыл прочитать его в новую матрицу. У меня есть вопрос, а что если большая матрица не является частью файла? Что, если пользователь вводит матрицу в массив, а затем ему нужно извлечь из него подматрицу. Как изменится синтаксис scanf? - person NLed; 09.05.2010
comment
Да стандартный ввод. Я попытался сделать это и заменить образец исходным массивом. Я получил это: scanf(matrix[i][j],%*[^\n]\n,&sub[i][j]); -- Где sub - это массив подматриц... но это не сработало... Это дает ошибку. Аргумент № 1 "scanf" должен быть типа "‹ptr›char", а не "float" - person NLed; 09.05.2010
comment
Это моя усовершенствованная функция сканирования: scanf(%*[^\n]\n,matrix[i][j],&sub[i][j]); -- Это правильно ? - person NLed; 09.05.2010
comment
@ZaZu, если у вас уже есть числа в памяти (будь то массив или любая другая структура данных), вам больше не нужен scanf - вы можете просто присваивать значения напрямую. Смотрите мое обновление, даже если это не совсем то, что вы хотите (поскольку я не уверен, что правильно понимаю), надеюсь, оно укажет вам правильное направление. - person Péter Török; 09.05.2010
comment
Спасибо за информацию, так что для варианта выбора подматрицы из чисел в памяти я должен использовать только этот цикл? Хорошо, звучит хорошо, но должен ли я объявлять array[] как новый массив? Или я могу использовать матрицу[][] ? - person NLed; 09.05.2010
comment
@ZaZu, я использовал массив, потому что в своем комментарии выше вы упомянули, что пользователь вводит матрицу в массив. Для матрицы самый внутренний оператор в цикле должен быть submatrix[i][j] = bigmatrix[y + i][x + j] - person Péter Török; 09.05.2010
comment
@Peter, теперь я понял: пользователь вводит матрицу 3 на 3. Затем для извлечения выбирает строку 2 и столбец 2. Если большая матрица была [ 1 1 1 ] [1 2 3 ] [ 1 4 5], они должны извлечь [ 2 3 ] [ 4 5 ]. Я получаю первое число (2), а затем программа дает сбой. Все, что я сделал, это добавил bigmatrix[i+col][j+row] .. разве это не правильно? - person NLed; 09.05.2010
comment
@ZaZu, ты уверен, что получил 2, а не 5? Обратите внимание, что в C/C++ массивы индексируются с 0, поэтому элемент в середине матрицы 3x3 будет bigmatrix[1][1]. Вы всегда должны четко понимать, используете ли вы индексы на основе 0 или 1 в своих расчетах. - person Péter Török; 09.05.2010
comment
@ Питер, Хм, да, ты прав. Ну, я не знаю, что случилось, я не получаю никакого числа.. Он просто падает, прежде чем выдает 2 или 5 ... должно быть [i+col][j+row] верно? - person NLed; 09.05.2010
comment
@ZaZu, так как кажется, что ваши row и col основаны на 1, вы должны уменьшить их на 1 при расчетах индекса, то есть bigmatrix[i+col-1][j+row-1]. - person Péter Török; 09.05.2010
comment
@Peter .. AHHHH, это помогло, я шел впереди столбца и строки на 1, верно? из-за этого он разбился? Что вы имеете в виду на основе 1? Я начинаю цикл с i=0 и увеличиваю до i‹2. Разве это не 0? он начинается с 0:S .. Пожалуйста, объясните! Спасибо - person NLed; 09.05.2010
comment
@Peter, есть ли способ проверить, действителен ли ввод пользователя для столбца и строки для большей матрицы? например, если они вводят col=row=4, а большая матрица всего 3x3... как я могу это сделать? Оператор do-while кажется подходящим, но как я могу проверить значение в одной части массива? bigmatrix[i][j] .. можно поставить while(col<=bigmatrix[i+col-1][j] && row<=bigmatrix[i][j+row-1]) ? - person NLed; 09.05.2010
comment
@ZaZu, if (row <= bigmatrixRows && col <= bigmatrixCols) { // do the copying } else { // display an error message } - person Péter Török; 09.05.2010
comment
Спасибо, работает отлично, я забыл сослаться на структуру, которая у меня есть. Я очень ценю, что вы поддерживали меня все это время, большое спасибо. - person NLed; 09.05.2010

Давайте рассмотрим это поэтапно. Сначала пара мелких исправлений в вашем коде:

for(i=0;i<rows;i++){
  for(j=0;j<cols;j++){
    float dummy;  /* this will make thing easier later */
    fscanf(sample,"%f",&dummy);
    matrix[i][j] = dummy;
  }
/* fscanf(sample,"\n",&matrix[i][j]); this isn't even legal */
}

Теперь мы определяем, что мы хотим:

int startrow = 2; /* The starting index. Remember we index 0,1,2,3 */
int startcol = 2;
int resultrows = 2; /* How many rows we want in our answer */
int resultcols = 2;
float result[resultrows][resultcols];

Теперь мы игнорируем то, что нам не нужно:

for(i=0;i<rows;i++){
  for(j=0;j<cols;j++){
    float dummy;
    fscanf(sample,"%f",&dummy);
    if(i >= startrow && i < startrow + resultrows &&
       j >= startcol && j < startcol + resultcols){
      matrix[i][j] = dummy;
    }
  }
}

Обратите внимание, что теперь в matrix копируются только нужные нам значения, остальная часть matrix — неинициализированная тарабарщина. Теперь вместо этого запишите его в result:

for(i=0;i<rows;i++){
  for(j=0;j<cols;j++){
    float dummy;
    fscanf(sample,"%f",&dummy);
    if(i >= startrow && i < startrow + resultrows &&
       j >= startcol && j < startcol + resultcols){
      result[i-startrow][j-startcol] = dummy;
    }
  }
}

EDIT:
Если вы хотите скопировать подматрицу из более крупной матрицы, которая уже находится в памяти, внутренний цикл должен быть

for(j=0;j<cols;j++){
  if(i >= startrow && i < startrow + resultrows &&
     j >= startcol && j < startcol + resultcols){
      result[i-startrow][j-startcol] = matrix[i][j];
  }
}
person Beta    schedule 09.05.2010
comment
Большое спасибо, что нашли время и написали это, я тестирую это и, надеюсь, я заставлю его работать. Спасибо - person NLed; 09.05.2010
comment
Я пытался использовать ваш метод, но я предпочел способ Питера, потому что он похож на то, как дается мой курс.. Спасибо, правда, очень ценю это. - person NLed; 09.05.2010

Хитрость заключается в том, чтобы заставить компилятор рассматривать ваш конкретный элемент массива как начальную точку вашей матрицы; следующий фрагмент кода делает это:

(int(*)[SIZE_OF_2ND_DIM])(&a[4][3])

Следующая программа фиксирует намеченную цель:

#include <stdio.h>

int num;

void print( int a[][num], int row, int col )
{
  int i, j;
  for(i = 0; i < row; i++)
  {
    for(j = 0; j < col; j++)
      printf("%3d ", a[i][j]);
    printf("\n");
  }
}


int main()
{
  int a[10][10];
  int i, j;

  for(i = 0; i < 10; i++)
    for(j = 0; j < 10; j++)
      a[i][j] = i*10+j;

  num = 10;
  print(a, 10, 10);

  printf("\n\n");

  print((int(*)[num])(&a[4][3]), 5, 4);

  return 0;
}

Вот соответствующий вывод:

  0   1   2   3   4   5   6   7   8   9
 10  11  12  13  14  15  16  17  18  19
 20  21  22  23  24  25  26  27  28  29
 30  31  32  33  34  35  36  37  38  39
 40  41  42  43  44  45  46  47  48  49
 50  51  52  53  54  55  56  57  58  59
 60  61  62  63  64  65  66  67  68  69
 70  71  72  73  74  75  76  77  78  79
 80  81  82  83  84  85  86  87  88  89
 90  91  92  93  94  95  96  97  98  99


 43  44  45  46
 53  54  55  56
 63  64  65  66
 73  74  75  76
 83  84  85  86
person LKB    schedule 06.01.2016