我需要帮助了解如何在C中使用点算法的点算法。我使用这个网站(http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/)作为参考(使用示例1,单个指针)。
int numRows = 2;
int numColumns = 3;
double * arrayMatrix = malloc(numRows * numColumns * sizeof(double));
int row = 0;
int column = 0;
printf("\nPlease enter the elements of your augmented matrix:\n");
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
printf("A[%d][%d]:", row + 1, column + 1);
scanf("%lf", &arrayElement);
printf("\n");
*(arrayMatrix + row * numColumns + column) = arrayElement;
//arrayMatrix[row + numColumns + column] = arrayElement;
}
}
// TEST PRINT
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
printf("%5.2lf", *(arrayMatrix + row * numColumns + column));
//printf("%5.2lf", arrayMatrix[row + numColumns + column]);
}
printf("\n");
}
我需要帮助理解这是否是将数据输入2D数组的正确方法,以及它是否也是从2D数组打印数据的正确方法。我将第1行的示例数据用作{1,2,3}和第2行为{1,2,3};但是当打印出所有6个元素时,我得到的信息都是0。
我也用这个答案作为参考(How to use pointer expressions to access elements of a two-dimensional array in C?)。具体遵循以下这一行:
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
但是我使用的是双指针而不是整数,但我不知道这是否会导致我的问题,或者是否是其他问题。
编辑 - 稍微更新了代码,但它仍然无法正常工作。
编辑2:这是我最近尝试开始工作的代码的最新更新。从阵列输入和打印数据的所有3种方式都会得到相同的结果(对于数组中的所有值都是0&#39;)
int numRows = 2;
int numColumns = 3;
//double * arrayMatrix = malloc(numRows * numColumns * sizeof(double));
double (*arrayMatrix)[numColumns] = malloc(sizeof(double[numRows][numColumns]));
int row = 0;
int column = 0;
printf("\nPlease enter the elements of your augmented matrix:\n");
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
printf("A[%d][%d]:", row + 1, column + 1);
scanf("%lf", &arrayElement);
printf("\n");
//*(arrayMatrix + row * numColumns + column) = arrayElement;
//arrayMatrix[row + numColumns + column] = arrayElement;
arrayMatrix[row][column] = arrayElement;
}
}
// TEST PRINT
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
//printf("%5.2lf", *(arrayMatrix + row * numColumns + column));
//printf("%5.2lf", arrayMatrix[row + numColumns + column]);
printf("%5.2lf", arrayMatrix[row][column]);
}
printf("\n");
}
答案 0 :(得分:5)
我想我明白你想做什么。在我们讨论代码之前,让我们回顾一下并稍微了解一下可以在C中模拟2D数组的不同方法。您有两种基本方法。您可以静态或动态声明一个数组array[row][col] = {{r0c0, r0c1, r0c2, ...}, {r1c0, r1c1, r1c2, ...} ... };
,它将创建一个单独的内存块,值顺序存储r0c0, r0c1, r0c2, ..., r1c0, r1c1, r1c2, ...
。,或者您可以创建row
个指针,每个指针指向单个col
元素数组。第二种方法(每个指向row
元素数组的col
指针数)在内存中不需要是顺序的。它可以,但不要求它。
数组索引表示法array[i][j]
将负责处理顺序内存块中的偏移量,以提供对任何单个元素的访问。对于访问col
指向的单个array[i]
个大小数组中的任何元素,情况也是如此。但究竟发生了什么?
让我们看一下简单的4元素数组的符号,比如array[4]
。要访问任何元素,您可以请求任何元素array[0]
到array[3]
访问所有4个元素。什么是array[2]
真的?你知道array
也是一个指针。您知道要访问指针所占地址的值,您需要取消引用指针。要访问array[0]
,您只需编写*array
,但如何使用指针表示法访问第二个元素?
正如我们前面所讨论的,声明为我们声明此示例的数组中的所有元素都按顺序存储在内存中。因此,要访问数组中的任何元素,您只需要从数组的开头偏移。既然您知道数组的起始地址只是array
,那么如果您想要第二个元素,则需要从头开始或1
访问元素偏移*(array + 1)
- 试试吧。实际上,您可以使用0-3
从*(array + i)
开始访问偏移i
处的所有元素,其中0-3
是*array
中的数字。
回顾一下,这也解释了为什么只需使用*(array + 0)
即可访问数组中的第一个元素。如果您为第一个元素编写了完整语法+ 0
- 并且您知道*array
无效,那么您可以使用*(array + 0) = *array
访问第一个元素,因为{ {1}}。
好的,2D案例怎么样?如果array[x]
是*(array + x)
,那么array[x][y]
是什么?分解。您知道可以将array[x]
写为*(array + x)
,因此array[x][y]
可以写为*(array + x)[y]
(如果我们暂时将stuff
替换为*(array + x)
,我们可以写stuff[y]
。我们知道如何用指针表示法编写它:*(stuff + y)
,对吗?现在只需用*(array + x)
代替stuff
就可以获得*(*(array + x) + y)
这是用于以模拟的2D数组方式访问顺序内存块中的任何元素的完整指针符号,这就是当您编写array[x][y]
时场景背后发生的事情。
现在让我们谈谈指针算术。声明指针时,您声明指向特定type
的指针(void
除外)。 type
告诉编译器如何使用该指针处理算术。例如,如果您声明:
char array[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
char *p = array;
编译器知道每个char
占用1-byte
个内存,因此当您编写*(p + 1)
时,您要求char
值1-byte
来自array
的开头。如果你写p++;
然后*p
,情况也是如此。但是会发生什么:
int array[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
int *p = array;
由于知道type
为int
并且int
为4-bytes
(取决于平台),因此当您撰写*(p + 1)
或{{1你将获得数组中的第二个元素,但是从数组的开头是值p++; *p;
。 4-bytes
告诉编译器如何处理任何给定值的指针算术(即偏移)。
你可以用一个最小的例子来解决这个问题:
type
<强>输出强>
#include <stdio.h>
#define ROWS 2
#define COLS 2
int main (void) {
int a[ROWS][COLS] = {{ 1, 2 }, { 3, 4 }};
int *p = *a;
int i, j;
for (i = 0; i < ROWS; i++) {
for (j = 0; j < COLS; j++)
printf (" %2d", a[i][j]);
putchar ('\n');
}
/* using a pointer to access the values */
for (i = 0; i < ROWS * COLS; p++, i++)
printf (" %2d", *p);
putchar ('\n');
return 0;
}
现在谈谈你实际问的问题。鉴于我们已经讨论过的所有事情,你宣布什么时宣布:
$ ./bin/array_min
1 2
3 4
1 2 3 4
你是在为什么指针声明和分配空间?指向具有double (*arrayMatrix)[NCOLS] = calloc (NROWS, NCOLS * sizeof **arrayMatrix);
元素的doubles
数组的指针。你有多少人需要持有完整的阵列?对于每个包含NCOLS
个元素的数组,您需要NROWS
个指针。请注意,使用NCOLS
代替calloc
。语法和它们的作用都有一个重要但微妙的区别。 malloc
将为您分配内存,但该内存未初始化且可包含各种内容。 malloc
也分配,但随后将内存初始化为零。在处理数值数组时,这对于防止意外访问未初始化元素(导致未定义的行为)非常有用。结果是calloc
和malloc
之间存在边际速度差异,但是您很难在少于百万分配的任何内容中找到可衡量的差异。< / p>
在此背景下,再次考虑您要做的事情。只需很少的调整,如果你做了类似的事情,你就会更有意义:
calloc
<强>输出强>
#include <stdio.h>
#include <stdlib.h>
#define NROWS 2
#define NCOLS 3
int main (void) {
size_t row = 0;
size_t col = 0;
/* allocate NROWS (array of pointers to NCOLS doubles). using
* calloc will allocate and initialize all elements to zero.
*/
double (*arrayMatrix)[NCOLS] = calloc (NROWS, NCOLS * sizeof **arrayMatrix);
/* prompt user for input, validate a proper value is entered */
printf("\nPlease enter the elements of your augmented matrix:\n");
for(row = 0; row < NROWS; row++)
{
for(col = 0; col < NCOLS; col++)
{
while (printf(" A[%zu][%zu]: ", row + 1, col + 1) &&
scanf("%lf", &arrayMatrix[row][col]) != 1)
printf("\n");
}
}
/* printf the array of pointers */
printf ("\n The matrix entered was:\n\n");
for(row = 0; row < NROWS; row++)
{
for(col = 0; col < NCOLS; col++)
{
printf(" %5.2lf", arrayMatrix[row][col]);
}
printf("\n");
}
free (arrayMatrix);
return 0;
}
内存错误/泄漏检查
在你的动态分配内存的任何代码中,你有2个责任关于任何分配的内存块:(1)总是保留一个指向内存块起始地址的指针,所以,(2)它可以在释放时释放它不再需要了。您必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,并确认已释放已分配的所有内存。对于Linux $ ./bin/arraymatrix
Please enter the elements of your augmented matrix:
A[1][1]: 1
A[1][2]: 2
A[1][3]: 3
A[2][1]: 4
A[2][2]: 5
A[2][3]: 6
The matrix entered was:
1.00 2.00 3.00
4.00 5.00 6.00
是正常的选择。有许多微妙的方法来滥用可能导致实际问题的内存块,没有理由不这样做。每个平台都有类似的记忆检查器。它们都很简单易用。只需通过它运行您的程序。
valgrind
如果您还有其他问题,请与我们联系。我的手指累了。结果比我预期的要长得多......
答案 1 :(得分:0)
这是一个函数,它将分配一个连续的2d双数组:
double* alloc_array_2d(int Width, int Height){
return (double*)malloc(Width * Height * sizeof(double));
}
这是一个函数,它将根据x和y坐标获得指向数组元素的指针:
double* get_element_2d(double* Array, int Width, int X, int Y){
int index = (Width * Y) + X;
return Array[index];
}
使用这种方法可以想象一个5 x 3阵列看起来像这样:
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
在计算机内存中它实际上是这样的:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
基本思想是一行值的开头位于前一行值的末尾旁边,因此通过将数组的宽度乘以垂直坐标,可以将索引偏移到正确的行中。例如,要访问第二行(7)中的第三个对象,我们调用
get_element_2d(myArray, 5, 2, 1); // 1 * 5 + 2 = 7
请注意,每个坐标都从零开始,就像所有指针算术一样,因此要访问第一行中的元素,您将使用get_element_2d(Array, Width, X, 0)
答案 2 :(得分:0)
如果您之前有double arrayElement;
,那么您的第一个代码示例看起来是正确的。
但是,如果您将其作为int arrayElement;
或其他一些数据类型,则会解释您所看到的内容,因为%lf
只能与double
一起使用。
现代编译器能够对此问题发出警告,因此您可以调查正在使用的编译器开关,以确保获得最大可能的警告级别。
要避免此错误,您可以直接扫描到数组中:
scanf("%lf", &arrayMatrix[row * numColumns + column]);
NB。您似乎已经获得了访问数组的每一行的替代变体,您可以从指针表示法更改为索引表示法。一般来说,索引表示法被认为更容易阅读,因此更可取。