【发布时间】:2021-05-22 12:04:09
【问题描述】:
最近我在思考这个问题:如何用一种更简单的方法来迭代 C 中的指针数组。
如果我在 C 中创建一个字符串数组,它应该看起来像这样吧?
int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;
但问题是,当您出于某种原因(例如打印其中的所有值)要迭代此数组时,您必须跟踪其当前大小,并将其存储在另一个变量中。
这不是问题,但是如果您创建大量数组,则必须在代码中跟踪它们的每一个大小。如果将此数组传递给另一个函数,则也必须传递它的大小。
void PrintValues (char ** arr, int size) {
for (int i = 0; i < size; i++)
printf("%s\n", arr[i]);
}
但是当迭代一个字符串时,情况就不同了。您有 '\0' 字符,它指定字符串的结尾。所以,你可以像这样迭代一个字符串,而不需要保持它的大小值:
char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
for (int i = 0; str[i] != '\0'; i++)
printf("%c", str[i]);
printf("\n");
现在我的问题: 在指针数组中分配 +1 单元以保持其尾部为 NULL 是否可以或在道德上正确?
char ** strArr = (char **) malloc(sizeof(char *) * (5 +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated
然后我可以使用 NULL 指针来控制迭代器:
void PrintValues (char ** arr) {
for (int i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
这将帮助我保持代码更简洁,尽管它会消耗更多内存,因为指针大小大于整数大小。
另外,当使用基于事件的库(如 Gtk)进行编程时,大小值会在某个时候从堆栈中释放,因此我必须创建一个指针来动态存储大小值。
在这种情况下,可以这样做吗?还是被认为是坏事?
这种技术是否只用于 char 指针,因为 char 类型的大小只有 1 个字节?
我怀念在 C 中使用 foreach 迭代器...
【问题讨论】:
-
这对我来说似乎很好。旁注:
malloc()在 C 中的转换结果是 discouraged。 -
NULL终止数组很常见 - 这正是argv的工作原理。 -
您使用
malloc(sizeof(char *) * size)分配的只是一些内存,一个连续的字节区域。编译器实际上并不知道您分配了多少内存,特别是如果size的值是在运行时设置的。返回的指针是指向已分配内存的第一个字节的指针。这个指针实际上是编译器所拥有的。因此,您可以跟踪分配的内存大小,并将其传递给需要它的函数。如果您使用特殊的终止符或使用“元素数”值并不重要,只要您保持跟踪即可。 -
@Oka 除了在 argv 的情况下,您还有 argc 并且循环迭代
for(size_t i=0; i<argc; i++)可能比在 argv 中查找 NULL 更有效。 -
@CarlHR 并不是真的气馁,只是毫无意义,因为您使用的是千禧年制造的 C 编译器。这里有一些关于 SO 的风格之战,特别是关于是否演员。
标签: arrays c for-loop iteration dynamic-memory-allocation