我想创建一个存储排列序列的动态数组,例如
order[0][]={1,2,3}
order[1][]={2,1,3}
order[2][]={2,3,1}
假设顺序[m] [n],m =排列数,n =项数,m和n是实时识别的。
我做了以下操作,发现指针地址重叠,导致存储值不正确。如何通过双指针正确使用动态数组?
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
/* debug only */
for(y=num_term, x=0; y>0; y--, x++){
term[x] = y;
}
fprintf(stderr, "\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %-11d", x);
}
printf("\n");
for(y=0; y<num_permute; y++){
printf("%-5d%12p", y, (order+y));
memcpy(&(order[y]), term, sizeof(term));
for (x=0; x<num_term; x++)
printf(" %12p", order+y+x);
printf("\n");
}
}
int main(){
int y, z;
int** x;
x = (int*) malloc(5*5*sizeof(int*));
permute(5, 5, x);
printf("\n");
printf("x ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<5; y++){
printf("%-4d", y);
for(z=0; z<5; z++){
printf(" %2d ", *(x+y+z));
}
printf("\n");
}
free(x);
return 0;
}
结果:订单[0] [1]和订单[1] [0]指向同一地址......其他人也是如此。以行为主轴,列为次要列:
order 0 1 2 3 4 0 0x100100080 0x100100080 0x100100084 0x100100088 0x10010008c 0x100100090 1 0x100100084 0x100100084 0x100100088 0x10010008c 0x100100090 0x100100094 2 0x100100088 0x100100088 0x10010008c 0x100100090 0x100100094 0x100100098 3 0x10010008c 0x10010008c 0x100100090 0x100100094 0x100100098 0x10010009c 4 0x100100090 0x100100090 0x100100094 0x100100098 0x10010009c 0x1001000a0 x 0 1 2 3 4 0 5 5 5 5 5 1 5 5 5 5 4 2 5 5 5 4 3 3 5 5 4 3 2 4 5 4 3 2 1
答案 0 :(得分:4)
源代码:
代码将类似于:
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
}
概念:
array
是一个指向指针的指针:在第一级,它指向一个指针块,每行一个指针。第一级指针是第一个被分配的指针;它有nrows
个元素,每个元素都足以容纳pointer-to-int
或int *
。如果分配成功,则用指针(也从nrows
获得)到malloc
个数量的指针填充指针(它们的所有ncolumns
),该行的存储为阵列。
画报描述:
如果您将情况可视化为:
,则很容易理解
考虑到这一点,示例代码可以重写为:
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
int* ptr = NULL;
for (y=num_term, x=0; y>0; y--, x++) {
term[x] = y;
}
printf("\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %2d ", x);
}
printf("\n");
for (y=0; y<num_permute; y++) {
ptr = order[y];
memcpy(ptr, term, sizeof(term));
printf("%-5d%12p", y, ptr);
for (x=0; x<num_term; x++) {
printf(" %2d ", ptr[x]);
}
printf("\n");
}
}
int main() {
int y, z;
int** x = NULL;
int num_term = 5;
int num_permutation = 5;
int* pchk = NULL;
x = (int**) malloc(num_permutation * sizeof(int*));
for (y=0; y<num_permutation; y++){
x[y] = (int*) malloc(num_term * sizeof(int));
printf("x[%d]: %p\n", y, x[y]);
}
permute(num_permutation, num_term, x);
printf("\nx: ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<num_permutation; y++){
pchk = x[y];
printf("%-4d", y);
for(z=0; z<num_term; z++){
printf(" %2d ", pchk[z]);
}
printf("\n");
}
for (y=0; y<num_permutation; y++) {
free(x[y]);
}
free(x);
return 0;
}
答案 1 :(得分:2)
代码示例仅模拟多维数组,并且操作不正确。要查看出现了什么问题,首先要考虑在声明多维数组时会发生什么:
int foo[3][5];
这将分配一个大小为3 * 5 * sizeof(int)的连续内存区域。在诸如foo[i]
的表达式中,foo
被转换为int [5]
指针,然后应用索引运算符。换句话说,foo[i]
相当于*( (int (*)[5])foo) + i)
。每个foo[i]
将被视为具有5 * sizeof(int)的大小。
x,y: 0,0 0,1 0,2 0,3 0,4 1,0 foo --> | 1 | 2 | 3 | 4 | 5 | 1 |... <- 5 * sizeof(int) ->
在示例代码中创建x
时,您正在复制此类型的多维数组。您正在使用的索引表达式(*(order + y + x)
)因此错误,因为它无法正确处理order[y]
:order + 1 + 0 == order + 0 + 1
的大小,这是您在样本输出。
正确的表达式是:(order + num_term * y)
用于y th 排列,*(order + num_term * y + x)
用于元素order[y][x]
。
这表明样本中存在另一类错误。对于这种模拟的多维数组,数组类型实际上是指向单维数组的指针。声明的x
和order
类型应为int*
,而不是int**
。这应该通过示例代码应该生成的类型警告来加强:
x
分配空间时,指针的类型(int*
)与x
x
的元素时,*(x+y+z)
的类型与格式“%d”不匹配。但是,在模拟多维数组时节省空间,使用时更容易出错(除非您编写一个函数来处理索引)。像Als'这样的解决方案可能更安全,因为您可以使用标准索引操作符。
答案 2 :(得分:1)
如果你有C99(或C11),用指针数组模拟一个2D数组是一个完全的过度杀伤。只需使用
void permute(size_t num_permute, size_t num_term, unsigned order[][num_term]);
作为您的函数签名,并在main
中使用
unsigned (*order)[m] = malloc(sizeof(unsigned[n][m]));
另外,正如您在上面的示例中所看到的,我建议您使用语义正确的类型。 size_t
最适合使用尺码,您的排列值看起来好像永远不会消极。也许对于这些你也应该从0
开始计算。
答案 3 :(得分:0)
以下代码段为给定的行和列创建了一个2d矩阵。请将此作为调试程序的参考。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int row, column;
int **matrix;
int i, j, val;
printf("Enter rows: ");
scanf("%d", &row);
printf("Enter columns: ");
scanf("%d", &column);
matrix = (int **) malloc (sizeof(int *) * row);
if (matrix == NULL) {
printf("ERROR: unable to allocate memory \n");
return -1;
}
for (i=0 ; i<row ; i++)
matrix[i] = (int *) malloc (sizeof(int) * column);
val=1;
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
matrix[i][j] = val++;
}
}
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
/*
Allocation of 2d matrix with only one call to malloc and
still get to access the matrix with a[i][j] format
the matrix is divided into headers and data.
headers = metadata to store the rows
data = actual data storage - buffer
allocate one contigious memory for header and data
and then make the elements in the header to point to the data are
<- headers -----><----------- data -----------
-----------------------------------------------------------------
| | | | | | .. |
| | | | | | .. |
-----------------------------------------------------------------
| ^
| |
|-----------------|
header points to data area
*/
/*
Output:
$ gcc 2darray.c
$ ./a.out
Enter rows: 10
Enter columns: 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
$
*/