【问题标题】:change #define value based on user input根据用户输入更改#define 值
【发布时间】:2019-03-08 17:52:05
【问题描述】:

我有一组如下所示的代码:

#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,程序将继续运行。

我尝试了以下链接,但它对我不起作用。 Array definition - Expression must have a constant value

我将不胜感激。谢谢!

【问题讨论】:

  • 当您在声明之前访问input 时,您为什么期望int input = scanf("%d", &input); 起作用???
  • @PSkocik:这个家伙说:“如果我尝试将 SEG 从 #DEFINE 更改为简单的 int SEG = 0”,这意味着他并没有尝试更改编译时常量(所有你需要做的就是在开场白之外读一点)。
  • 在哪里你声明int SEG = 0;?请显示不起作用的代码,而不是起作用的代码
  • 看起来真正的问题是关于动态分配或 VLA。

标签: c


【解决方案1】:

#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);

像访问原始二维数组一样访问它。 memory[row][col];

【讨论】:

  • 问题是:“如果我尝试将 SEG 从 #DEFINE 更改为简单的 int SEG = 0”,这意味着这个家伙不是试图更改预处理器指令(如果您只是费心阅读开篇声明之外的内容,您可能已经知道了)。
  • @goodvibration 但 Mini 的重点是使用 malloc 作为不使用预处理器指令的方式。
  • 请为尺寸添加阅读用户输入,以使其成为更好的答案。
  • @Mini 最好只分配一次内存,而不是为每个块分配一次。
  • @MarlinPierce 你是对的,但这种方式允许像 [i][j] 这样的访问,这是我相信 OP 想要的
【解决方案2】:

#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]

【讨论】:

    【解决方案3】:

    C 中的数组是非常基本的。多维数组只是数组的数组;所以当你说:

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

    你也可以写得很好:

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

    为什么是 37? 3*11 + 4 = 37。

    编译器如何知道乘以 11?你在 A 的定义中告诉过它!

    不满足于 const 和 volatile 的灾难,标准 [原文如此] 正文将动态数组大小添加到数组的特殊情况,允许这种白痴:

    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;
         }
    }
    

    【讨论】:

      【解决方案4】:

      对于 C89 及更早版本,数组声明中的数组维度必须是常量表达式,这意味着它们必须在编译时可计算(数字常量、sizeof 表达式、涉及数字常量的表达式和/或 sizeof 表达式,或扩展为之前任何一个的宏)。

      C99 引入了“可变长度数组”,其中数组尺寸使用运行时表达式确定(这对 VLA 的使用位置设置了一些限制):

      int blocks = some_value();
      int seg = some_other_value();
      
      int memory[blocks][segs];
      

      不幸的是,Microsoft 的 Visual Studio 实现不支持可变长度数组(或 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();
      

      编辑

      这是一个基于您问题中的 sn-p 的(未经测试!)示例 - 您正在尝试读取具有固定行数 (BLOCKS) 和可变列数 (@987654333) 的 .csv 文件@):

      #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;
      }
      

      【讨论】:

      • 嗨,我试过这个,我的记忆变成了-10923481948。这是否意味着存在堆栈溢出?
      • @Python_new:你的意思是什么,你的记忆“变成”了那个价值?你到底尝试了什么?您是如何检查该值的?
      • 我尝试使用这种方式打印出来 for (b = 0; b
      • @Python_new: malloc 不需要初始化它分配的内存,所以每个memory[b][s] 的初始值是indeterminate。以我的编辑为例。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-13
      • 1970-01-01
      • 2012-09-12
      • 2015-06-22
      • 1970-01-01
      相关资源
      最近更新 更多