简体   繁体   English

根据用户输入构造2D数组的正确方法

[英]Correct way to construct a 2D array from user input

I know that there have been many questions belonging to the family of "multi-dimensional arrays". 我知道有很多问题属于“多维数组”家族。 Since I couldn't find a specific question which clears my issue, I am finally asking it. 由于我找不到能解决问题的特定问题,因此我终于要提出了。

Objective : Store a 2D array whose values are input from the user. 目标 :存储一个二维数组,其值是从用户输入的。


Method-01 : Using arbitrarily large initial size for the array. 方法01 :为数组使用任意大的初始大小。

Code : 代码

int method_arbit()
{
 int n, m;
 int i, j;
 float myarray[100][100];

 printf("Enter the number of rows: ");
 scanf("%d", &m);

 printf("Enter the number of columns: ");
 scanf("%d", &n);

 for(i=0; i<m; i++)
 {
     for(j=0; j<n; j++)
         scanf("%f", &myarray[i][j]);
 }

 for(i=0; i<m; i++)
 {
     for(j=0; j<n; j++)
         printf("[%d][%d] = %f", i, j, myarray[i][j]);
 }
}

Comments : This function works as expected ! 评论 :此功能按预期工作!


Method-02 : Using dynamic memory allocation. 方法02 :使用动态内存分配。

Code : 代码

int method_dynamic()
{
 int n, m;
 int i, j;
 float **myarray; // m x n matrix

 printf("Enter the number of rows: ");
 scanf("%d", &m);

 printf("Enter the number of columns: ");
 scanf("%d", &n);

 myarray = malloc(m*sizeof(float*));
 for(i=0; i<m; i++)
     myarray[m] = malloc(n*sizeof(float));

 for(i=0; i<m; i++)
 {
     for(j=0; j<n; j++)
         scanf("%f", &myarray[i][j]);
 }

 for(i=0; i<m; i++)
 {
     for(j=0; j<n; j++)
         printf("[%d][%d] = %f", i, j, myarray[i][j]);
}
}

Comments : This method gives Segmentation Fault upon taking input. 注释 :该方法在输入时会给出细分错误。

Q1: I'm having a hard time debugging this. Q1:我很难调试此。 Moreover, I'm finding it even harder to understand the reasoning behind this behavior. 而且,我发现更难理解这种行为背后的原因。 I have a basic understanding of pointers and dynamic memory allocation. 我对指针和动态内存分配有基本的了解。 I would appreciate a detailed explanation of the mistake I am making and the concepts I might be overlooking. 我将对我所犯的错误以及可能忽略的概念进行详细说明。

Q2: Is it advisable to say that if we don't know the size of the array at compile time, we should always dynamically allocate the array? 问题2:建议您说,如果我们在编译时不知道数组的大小,那么应该始终动态分配数组吗?
OR 要么
When is it advisable to use a dynamically allocated array? 何时建议使用动态分配的数组? One use case I know is while dealing with functions and returning arrays from them. 我知道一个用例是在处理函数并从中返回数组时。

OP's problem is using the wrong index @forcebru OP的问题是使用了错误的索引@forcebru

 myarray = malloc(m*sizeof(float*));
 assert(myarray); // Do some allocation check;
 for(i=0; i<m; i++) {
     //         v----- here
     // myarray[m] = malloc(n*sizeof(float));
     myarray[i] = malloc(n*sizeof(float));   
     assert(myarray[i]);
 }

You can declare multidimension array as a big array. 您可以将多维数组声明为大数组。

 int n, m;
 int i, j;
 float* myarray; // m x n matrix

 std::cout<<"Enter the number of rows: \n";
 scanf("%d", &m);

 std::cout << "Enter the number of columns: \n";
 scanf("%d", &n);

 myarray = (float*)malloc( m * n * sizeof(float) );

 for(i=0; i<m; i++)
 {
     for (j = 0; j<n; j++) {
         scanf("%f", &(myarray[i * n  + j]));
     }
 }

 for(i=0; i<m; i++)
 {
     for(j=0; j<n; j++) {
         printf("[%d][%d] = %f", i, j, (myarray[i * n  + j]));
     }
 }

Q1 : you need a chunk of memory to hold a 2-d array of float's, your initial code of 问题1 :您需要一块内存来保存浮点数的二维数组,这是您的初始代码

float **myarray;
myarray = malloc( m * sizeof(float*) );

m = 3;   // for this example
n = 5;   // for this example

is a problem because your two dimensions are m and n . 这是一个问题,因为您的两个维度分别是mn You are not using n there. 您不在那里使用n Also you are doing sizeof(float*) and you don't want the size of a pointer to float . 另外,您正在执行sizeof(float*)并且您不希望指针的大小浮动 What is happening is, if sizeof( pointer to float) = { 8 bytes on a 64-bit system, 4 bytes on 32-bit system} then your malloc is reserving either 24 or 12 bytes respectively. 发生的是,如果sizeof( pointer to float) = {在64位系统上为8个字节,在32位系统上为4个字节},则您的malloc分别保留24或12个字节。 But for only m units of memory when you really need m x n units {15 units for 15 unique values, which are of type float}. 但对于只有内存单位为m,当你真正需要的M×N单元{15个单位15个不同的值,它是float类型}。

so you want the size that a single float takes up in memory. 因此,您需要单个浮点数占用内存的大小。 Therefore you should be doing 因此,你应该做

float *myarray;  // not a double pointer
myarray = (float *) malloc( m * n * sizeof( float ) );

for example if sizeof( float ) = 4 bytes, then if m=3 and n=5 then you get 4x15 = 60 bytes of memory allocated. 例如,如果sizeof(float)= 4个字节,则如果m = 3且n = 5,则得到4x15 = 60个字节的已分配内存。 malloc returns a pointer to that chunk of memory, and you cast it's type into your declared pointer to it. malloc返回一个指向该内存块的指针,然后将其类型转换为声明的指针。

At this point it is up to you to index into that total chunk of 60 bytes, where *myarray points to the beginning of it and that's it. 在这一点上,您可以索引整个60个字节的块,其中*myarray指向它的开头,仅此而已。 The compiler knows nothing else about how that chunk of memory is to be arranged or used other than the pointer to the beginning of it which is myarray and it is to a float data type. 除了指向内存的开头(即myarray的指针)和float数据类型的指针之外,编译器对如何安排或使用该内存块一无所知。 There is no way for malloc or the compiler to know the row or column size m and n which you are trying to use when you use the myarray[][] convention. 使用myarray[][]约定时,malloc或编译器无法知道要使用的行或列大小mn

On your system, if sizeof( float ) is 4, then every 4 bytes within that 60 byte chunk can be a float value, giving you 15 values. 在您的系统上,如果sizeof(float)为4,则该60字节块中的每4个字节可以是一个float值,为您提供15个值。

if you want to use the convention myarray[i][j] you cannot because you used malloc and it does not know how that 60 byte chunk of memory is divided up. 如果要使用约定myarray[i][j] ,则不能使用malloc,因为它不知道如何将60字节的内存块分割。 You will have to do the math of [row][col] indexing into myarray manually such as 您将必须手动将[row] [col]索引到myarray中,例如

m = 3;   // max rows
n = 5;   // max columns

row = 2;  // value entered by user, must be < m
col = 3   // value entered by user, must be < n

*(myarray + (row*n) + col) = 1.2345;

Q2: yes i think it is best if you don't know the size of memory you'll need, to write good code getting all user inputs then figuring out the size of memory you'll need. 问题2:是的,我认为最好是如果您不知道所需的内存大小,编写好的代码以获取所有用户输入,然后弄清楚所需的内存大小。 Then use either malloc or calloc to allocate that memory, and if not successful {system doesn't have enough} then you handle that condition and write code accordingly. 然后使用malloccalloc分配该内存,如果未成功{系统没有足够的空间},则可以处理该条件并相应地编写代码。 Only downside is if you write code that repeatedly calls malloc or calloc, then free's it and repeats this process many times, this can incur a lot of overhead. 唯一的缺点是,如果编写重复调用malloc或calloc的代码,然后释放它并重复此过程很多次,则可能会产生大量开销。

You will never do this "for real". 您永远不会“真正”做到这一点。 Getting user to enter a 2D matrix via stdin is a pedagogical toy problem to give to people learning C. One of the disadvantages of the exercise is that there isn't really a good answer, there are ways you can do it like creating an oversize buffer, or reallocating memory to grow, or querying the user for width and height before input of the variables. 让用户通过stdin输入2D矩阵是给学习C的人的教学玩具问题。该练习的缺点之一是没有很好的答案,有很多方法可以像创建超大尺寸一样来做。缓冲区,或者重新分配内存以增长,或者在输入变量之前向用户查询宽度和高度。 But nothing is entirely satisfactory. 但是没有什么是完全令人满意的。

In reality data is likely to come in a file format such as CSV. 实际上,数据很可能以CSV等文件格式出现。 Parsing a CSV file is fairly difficult, but not so difficult that any competent programmer shouldn't be able to achieve it. 解析CSV文件非常困难,但并不是那么困难,以至于任何合格的程序员都无法实现它。 The usual way is to read in the structure into a memory structure, then "parse the output of the parser" to get it into a flat 2D array (or 1D array of structures, quite common with CSV files). 通常的方法是将结构读入内存结构,然后“解析解析器的输出”以将其放入平面2D数组(或1D结构数组,这在CSV文件中很常见)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM