使用指针符号与数组符号相比有什么优势吗?我知道可能有一些特殊情况下指针符号更好,但在我看来,数组符号更加清晰明了。我的教授告诉我们他更喜欢使用指针符号“因为它是C语言”,但这不是他用来评分的标准。我知道用字符数组声明字符串与用指针声明字符串之间存在差异——我只是在谈论一般情况下遍历数组。
使用指针符号与数组符号相比有什么优势吗?我知道可能有一些特殊情况下指针符号更好,但在我看来,数组符号更加清晰明了。我的教授告诉我们他更喜欢使用指针符号“因为它是C语言”,但这不是他用来评分的标准。我知道用字符数组声明字符串与用指针声明字符串之间存在差异——我只是在谈论一般情况下遍历数组。
struct owner {
long refcount;
size_t size;
double data[]; /* C99 flexible array member */
};
struct matrix {
long rows;
long cols;
long rowstep;
long colstep;
double *origin;
struct owner *owner;
};
struct matrix
的本地变量来描述它。所有引用的数据都存储在动态分配的struct owner
结构中,以C99灵活数组成员的形式存在。当你不再需要该矩阵时,必须明确地“删除”它。这允许多个矩阵引用相同的数据:你甚至可以有单独的行、列或对角线向量,对其中任何一个进行更改会立即反映在所有其他向量上(因为它们引用相同的数据值)。struct matrix m
中的元素,行r
、列c
,假设0 <= r < m.rows
和0 <= c < m.cols
,你可以使用m.origin[r*m.rowstep + c*m.colstep]
。m.rows
和m.cols
以及m.rowstep
和m.colstep
。所有改变的只是读取数据(存储在所有者结构中)的顺序。origin
指向出现在矩阵中行0、列0处的双精度数;rowstep
和colstep
可以是负数。这允许各种奇怪的“视图”到否则单调的常规数据,如镜像和对角线等。)data
成员将必须是一个指针。这将意味着在硬件级别上需要额外的重定向(稍微减慢数据访问速度)。我们要么需要单独分配由data
指向的内存,要么使用技巧指向紧随所有者结构本身之后的地址,但适当地对齐为双精度数。#define MATRIXELEM(m, r, c) ((m).origin[(r)*(m).rowstep + (c)*(m).colstep])
这种方法的缺点是它评估第一个参数m
三次。(这意味着MATRIXELEM(m++,0,0)
实际上会尝试将m
增加三次。)在这个特定的情况下,m
通常是struct matrix
类型的局部变量,这应该会减少意外发生的可能性。例如,可以这样写:
struct matrix m1, m2;
/* Stuff that initializes m1 and m2, and makes sure they point
to valid matrix data */
MATRIXELEM(m1, 0, 0) = MATRIXELEM(m2, 0, 0);
i + 4*j
作为行时,索引计算是正确的((i + 4*j)*m.rowstep
而不是 i + 4*j*m.rowstep
)。在预处理器宏中,这些括号并不是真正的“额外”。除了确保正确的计算之外,使用“额外”括号也告诉其他程序员宏编写者已经小心避免了这样的算术相关错误。(我认为在这种情况下放置括号即使在语法不明确的情况下,也会向阅读代码的其他开发人员传达这种“保证”,因此应该被视为“好习惯”)。"Foo"[1]
很明显等于'o'
,而*("Foo"+1)
就没有那么直观了。(然而,1["foo"]
也不太显然,但您可以责怪C标准化人员的这个问题)