我写了一个程序涉及两行整数,它们会定期交换位置。所以,我所做的是分配两个单独的指向整数的指针,这些整数将模拟所需的行。然后我将两个指针放入一个常量指针数组中,这将很容易地进行交换。
我遇到的问题是完全错误。以此为例:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char* a = malloc(sizeof(char)*5);
char* temp[] = {a};
int i, h, k = 'a';
for(i = 0; i < 5; i++)
a[i] = k++;
for(i = 0; i < 5; i++)
printf("%c ", temp[0][i]);
free(a);
return 0;
}
输出:a b c d e
IdeOne
我偶然尝试通过二阶解除引用访问静态数组中包含的数组成员:&#34; [] []&#34;
我对这个事件的想法并不多,因为所有事情都编译好并且完美运行,甚至在输出中给出了预期的结果。当我运行内存分析并发现我遇到大量的寻址错误和所谓的内存泄漏时,问题出现了。
因此,为了开始调试过程,我想来到这里,并询问为什么这有效,以及它是否是有效的C语法。我的印象是:
temp[0]
会取消引用char*
,a
。然后,它将进一步取消引用a
来访问其成员。此外,我的印象是:
temp[row][col]
翻译为:
*(*(temp + row*col) + col)
在运行时。因此,temp[0][i]
的双重解除引用应该会偏离temp
而根本不会访问a
。
更有趣的是:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char* a = malloc(sizeof(char)*5);
char* b = malloc(sizeof(char)*5);
char* temp[] = {a, b};
int i, h, k = 'a', j = 'A';
for(i = 0; i < 5; i++){
a[i] = k++;
b[i] = j++;
}
for(i = 0; i < 5; i++){
for(h = 0; h < 5; h++)
printf("%c ", temp[i][h]);
puts("");
}
free(a);
free(b);
return 0;
}
在IdeOne运行时无法编译。但是,此代码在gcc
模式下使用Microsoft Visual Studio Professional 2013和c99
进行编译。
关于如何正确地做我试图做的事情的任何想法或建议?也就是说,访问静态数组a
中包含的成员b
和temp
,而不使用如下的非常丑陋的语法:
*(temp[i] + sizeof(char)*h)
答案 0 :(得分:3)
temp[row][col]
不等同于*(*(temp + row*col) + col)
,但实际上相当于*(*(temp + row) + col)
。
您的第二个示例代码不正确,因为temp
是一个包含2个元素的数组,但您访问的temp[i]
i
范围从0
到5
答案 1 :(得分:1)
当您认为temp[0]
等于a
且temp[1]
等于b
时,您猜对了。但是,等一下你为什么要超越那个,就像你试图取消引用像temp[2]
这样的东西?你没有正确地初始化这个东西!
您的程序通过访问数组末尾的内存导致undefined behaviour
。编译器并不总是有义务给你一个错误信息。查看this问题。
答案 2 :(得分:1)
C99标准§6.5.2.1¶2说 -
下标运算符
相同[]
的定义是E1[E2]
与(*((E1)+(E2)))
因此,表达式temp[row][col]
被评估为
temp[row][col] --> *((temp[row]) + col) --> *(*(temp + row) + col)
|_______| |
| |
E1 E2
而不是*(*(temp + row*col) + col)
。请注意区别。因此,你的第一个程序没问题。
在第二个程序中,声明
char* temp[] = {a, b};
将temp
定义并初始化为2
指向字符的数组。但是,在for
循环中,您可以temp[i][h]
访问数组,i
范围从0
到4
。访问数组范围之外的元素是未定义的行为。因此,你的第二个程序是错误的。