изменить значение #define на основе пользовательского ввода - PullRequest
1 голос
/ 08 марта 2019

У меня есть набор кодов, которые выглядят следующим образом:

#define BLOCKS 20
#define SEG 5

int memory[BLOCKS][SEG];

int main() {

    FILE* stream = fopen("file.csv", "r");

    printf("Please enter a number:");
    int input = scanf("%d", &input);

Если я попытаюсь изменить SEG с #DEFINE и просто int SEG = 0; и попытаться позволить int input = scanf("%d", &input); статьSEG, Visual studio сообщает мне, что мой SEG теперь является необъявленным идентификатором, а выражение для

int memory[BLOCKS][SEG];

должно иметь постоянное значение.

Мой вопрос: как мне сделатьэто SEG значение будет определяться пользовательским вводом?Например.если пользователь введет 10, моя переменная SEG станет 10, и программа продолжит работу.

Я попробовал следующую ссылку, но она не работала для меня. Определение массива - выражение должно иметь постоянное значение

Буду признателен за помощь.Спасибо!

Ответы [ 4 ]

0 голосов
/ 08 марта 2019

Массивы в Си очень простые.Многомерный массив - это просто массив массивов;поэтому, когда вы говорите:

int A[10][11];
...
A[3][4] = 17;

, вы могли бы точно так же написать:

int A[110];
...
A[37] = 17;

Почему 37?3 * 11 + 4 = 37.

Как компилятор узнал, что нужно умножить на 11?Вы сказали это в определении A!

Не удовлетворенный катастрофой const и volatile, тело стандарта [sic] добавило динамические размеры массивов в особый случай массивов, разрешив этот идиотизм:

void f(int n, int m) {
    int A[n][m];
    int i,j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            A[i][j] = i*m+j;
        }
    }
    int *a = A;
    for (i = 0; i < n*m; i++) {
        printf("%d\n", a[i]);
    }
}

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

int memory[A Very Big Number];
int *getmem(int blk, int segsize) {
     int off = blk * segsize;
     if (off >= 0 && off < A Very Big Number) {
         return memory + off;
     } else {
         return NULL;
     }
}
0 голосов
/ 08 марта 2019

A #define Значение директивы препроцессора должно быть известно во время компиляции и не может ожидать выполнения. Аналогично, объявление массива обычно необходимо знать во время компиляции.

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

int *memory = (int *)malloc(BLOCKS * input * sizeof(int))

Вы можете адресовать блок 2, сегмент 3 как

memory[ 3 * BLOCKS + 2]

или

memory[ seg * BLOCKS + block]

В качестве альтернативы, если вы хотите использовать нотацию двумерного массива, и вам не интересно, в каком порядке должны быть измерения, вы можете объявить указатель на массив,

typedef int (*memseg_t)[BLOCKS];
memseg_t memory = (memseg_t)malloc(BLOCKS * input * sizeof(int));

ссылка:

memory[seg][block]
0 голосов
/ 08 марта 2019

Для C89 и более ранних размеров размеры массива в объявлении массива должны быть константными выражениями , что означает, что они должны оцениваться во время компиляции (числовые константы, sizeof выражения, выражения с числовыми константами и / илиsizeof выражения или макросы, которые расширяются до любого из предыдущих).

C99 представил «массивы переменной длины», где размеры массива определяются с помощью выражений времени выполнения (что накладывает некоторые ограничения на использование VLA):

int blocks = some_value();
int seg = some_other_value();

int memory[blocks][segs];

К сожалению, реализация Microsoft Visual Studio в Microsoftне поддерживает массивы переменной длины (или многое другое, кроме C89).

Итак, у вас есть выбор - вы можете использовать другой компилятор, который поддерживает C99 или более позднюю версию (например, MinGW), или вам нужно будет использовать динамическое распределение памяти.Если вы хотите сохранить BLOCKS постоянной, но SEG переменной, вам нужно будет сделать что-то вроде этого:

int *memory[BLOCKS];
int seg;
...
scanf( "%d", &seg );
...
for ( int i = 0; i < BLOCKS; i++ )
{
  memory[i] = malloc( sizeof *memory[i] * seg );
  if ( !memory[i] )
    // handle memory allocation failure
}

Когда вы закончите, вам нужно free этой памяти:

for ( int i = 0; i < BLOCKS; i++ )
  free( memory[i] );

Основным недостатком этого метода является то, что строки массива не будут смежными в памяти - между memory[i][seg-1] и memory[i+1][0] будет разрыв.Если это имеет значение, вам, возможно, придется выделить память как один блок, а затем фальсифицировать 2D-индексацию:

int *memory = malloc( sizeof *memory * BLOCKS * seg );
if ( !memory )
  // handle memory allocation failure
...
memory[i * BLOCKS + j] = some_value();

РЕДАКТИРОВАТЬ

Вот пример (не проверенный!)в фрагменте вашего вопроса - вы пытаетесь прочитать файл .csv с фиксированным числом строк (BLOCKS) и переменным числом столбцов (SEG):

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

#define BLOCKS 20

int *memory[BLOCKS];

int main( void )
{
  int seg;
  FILE *stream = fopen( “file.csv”, “r” );
  if ( !stream )
    // print error and exit

  printf( “Please enter a number: “);
  if ( scanf( “%d”, &seg ) != 1 )
    // print error and exit

  for ( size_t b = 0; b < BLOCKS; b++ )
  {
    /**
     * Allocate memory for a block (row)
     */
    memory[b] = malloc( sizeof *b * seg );
    if ( !memory[b] )
      // print error and exit

    /**
     * Read that row from the file - since it has 
     * a .csv extension, I am assuming it is
     * comma-delimited.  Note that malloc is not
     * required to initialize memory to any specific
     * value - the initial value of each memory[b][s]
     * is indeterminate.
     */
    for ( size_t s; s < seg; s++ )
      if ( fscanf( stream, “%d%*c”, &memory[b][s] )) != 1 )
        // print error and exit
  }
  fclose( stream );

  /**
   * Do stuff with memory here
   */

  /**
   * After you’re done with memory, free it
   */
  for ( size_t b = 0; b < BLOCKS; b++ )
    free( memory[b] );

  return EXIT_SUCCESS;
}
0 голосов
/ 08 марта 2019

# define - это директива препроцессора.Вы не можете изменить его на основе пользовательского ввода в одной программе.Вы можете попытаться использовать malloc для создания массива!

Попробуйте

int input, i;

printf("Please enter a number:");
scanf("%d", &input);

int** memory = malloc(sizeof(int*) * BLOCKS);
for(i = 0; i < BLOCKS; i++)
    memory[i] = malloc(sizeof(int) * input);

Получите доступ к нему, как к исходному 2D-массиву.memory[row][col];

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