c语言 - 根据用户输入构建 2D 数组的正确方法



我知道有很多属于"多维数组"家族的问题。由于我找不到解决我问题的具体问题,我终于问了它。

目标:存储一个二维数组,其值来自用户输入。


方法-01:对数组使用任意大的初始大小。

代码

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

评论:此功能按预期工作!


方法-02:使用动态内存分配。

代码

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

注释:此方法在输入时给出分段错误。

Q1:我很难调试这个。此外,我发现更难理解这种行为背后的原因。 我对指针和动态内存分配有基本的了解。 我希望能详细解释我所犯的错误和我可能忽略的概念。

Q2:如果我们在编译时不知道数组的大小,我们应该始终动态分配数组,是否建议这样做?
或者
什么时候建议使用动态分配的数组? 我知道的一个用例是在处理函数并从中返回数组时。

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

您可以将多维数组声明为大数组。

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:你需要一大块内存来容纳浮点数的二维数组,你的初始代码

float **myarray;
myarray = malloc( m * sizeof(float*) );
m = 3;   // for this example
n = 5;   // for this example

是一个问题,因为你的两个维度是mn。 你在那里没有使用n。 此外,您正在执行sizeof(float*)并且不希望指针的大小浮动。 正在发生的事情是,如果sizeof( pointer to float)= { 64 位系统上为 8 个字节,32 位系统上为 4 个字节},则您的 malloc 分别保留 24 个或 12 个字节。 但是对于只有m 个内存单位,当您确实需要mxn个单位 {15 个单位表示 15 个唯一值,这些值是 float 类型}。

因此,您需要单个浮点数在内存中占用的大小。 因此你应该做

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

例如,如果 sizeof( float ) = 4 个字节,那么如果 m=3 和 n=5,那么你得到 4x15 = 60 字节的内存分配。 Malloc 返回指向该内存块的指针,并将其类型转换为指向它的声明指针。

此时,由您来索引到60字节的总块中,其中*myarray指向它的开头,仅此而已。 编译器不知道该内存块将如何排列或使用,除了指向它开头的指针,该指针myarray并且指向浮点数据类型。 malloc 或编译器无法知道您在使用myarray[][]约定时尝试使用的行或列大小mn

在您的系统上,如果 sizeof( float ) 为 4,那么该 60 字节块中的每 4 个字节可以是一个浮点值,为您提供 15 个值。

如果你想使用约定myarray[i][j]你不能,因为你使用了malloc,它不知道60字节的内存块是如何划分的。 您必须手动将 [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:是的,我认为最好是不知道所需的内存大小,编写良好的代码获取所有用户输入,然后计算出所需的内存大小。 然后使用malloccalloc来分配该内存,如果不成功 {系统没有足够的},那么您可以处理该条件并相应地编写代码。 唯一的缺点是,如果你编写的代码反复调用malloc或calloc,那么释放它并多次重复这个过程,这可能会产生很多开销。

你永远不会"真正"这样做。让用户通过 stdin 输入 2D 矩阵是一个教学玩具问题,要给学习 C 语言的人。该练习的缺点之一是没有一个好的答案,有一些方法可以做到这一点,例如创建一个超大的缓冲区,或重新分配内存以增长,或者在输入变量之前查询用户的宽度和高度。但没有什么是完全令人满意的。

实际上,数据可能以CSV等文件格式出现。解析CSV文件相当困难,但并不是任何有能力的程序员都无法实现的困难。通常的方法是将结构读入内存结构,然后"解析解析器的输出"以将其放入平面 2D 数组(或结构的 1D 数组,在 CSV 文件中很常见)。

相关内容

  • 没有找到相关文章

最新更新