哪一个,1个或2个,在任何方面都更好(无论什么都可以被认为更好)?它们完全一样吗?
void method1(char **var1) {
//the last element of var1 is NULL
char **var2 = var1;
int count = 0;
//1
for (; *var2; (*var2)++, count++);
//2
while(*var2) {
(*var2)++;
count++;
}
}
答案 0 :(得分:2)
你可以用编译器检查不同优化级别的asm输出......或者只是不要担心语义相同的东西...
...
LBB0_1: ## =>This Inner Loop Header: Depth=1
movq -16(%rbp), %rax
cmpq $0, (%rax)
je LBB0_4
## BB#2: ## in Loop: Header=BB0_1 Depth=1
jmp LBB0_3
LBB0_3: ## in Loop: Header=BB0_1 Depth=1
movq -16(%rbp), %rax
movq (%rax), %rcx
addq $1, %rcx
movq %rcx, (%rax)
movl -20(%rbp), %edx
addl $1, %edx
movl %edx, -20(%rbp)
jmp LBB0_1
LBB0_4:
...
.subsections_via_symbols
方法2:
...
LBB0_1: ## =>This Inner Loop Header: Depth=1
movq -16(%rbp), %rax
cmpq $0, (%rax)
je LBB0_3
## BB#2: ## in Loop: Header=BB0_1 Depth=1
movq -16(%rbp), %rax
movq (%rax), %rcx
addq $1, %rcx
movq %rcx, (%rax)
movl -20(%rbp), %edx
addl $1, %edx
movl %edx, -20(%rbp)
jmp LBB0_1
LBB0_3:
...
.subsections_via_symbols
答案 1 :(得分:2)
您的代码似乎完全错误,因为它增加了var2
指针的目标,这也用于结束循环。您不能指望递增值达到零。我将假设(1)你想增加临时指针迭代字符串的列表(技术上是一个数组)和(2)你期望一个NULL指针作为标记。
那么我们编写的代码的逻辑是什么?它需要一个字符串数组(文件中的行,名称列表等等),对项目进行计数,然后执行您需要执行的任何操作。输入参数由指向char的指针表示,这对于初学者来说可能有点混乱。指针在C中用于多个目的,一个用于指向列表的第一项(技术数组)。这是list
指针(类型char **
)的情况,它指向一个指针数组(每个类型char *
),而这些指针又指向一个字节/字符值数组(类型)每个char
。
因此,您需要增加一个本地char **
指针来迭代项目和一个临时char *
指针来迭代项目的字符。如果您只想读取数据,则除了本地(临时)变量之外,不得增加任何其他内容。递增*item
是无意义的,会以错误的方式改变数据(指针将指向第二个字符而不是第一个字符),并且将增量指针检查为NULL是双重废话。
换句话说,使用临时指针迭代数组的习惯用法需要以下操作:
使用C99语法,您可能希望执行以下操作:
void method1(char **list) {
size_t count = 0;
for (char **item = list; *item; item++)
count++;
...
}
较旧的语法强制您这样做:
void method1(char **list) {
char **item;
size_t count = 0;
for (item = list; *item; item++)
count++;
...
}
对于不熟悉指针的人来说,这是一个更直观的版本:
void method1(char **list) {
size_t count = 0;
for (size_t i = 0; list[i]; i++)
count++;
...
}
注意:count
是多余的,因为其值与i
的值保持一致,因此您可以for (; list[count]; count++)
使用空体或while (list[count]) count++;
只计算项目的真正功能是:
size_t get_size(char **list)
{
int count = 0;
for (char **item = list; *item; item++)
count++;
return count;
}
当然可以简化为(借用其他答案):
size_t get_size(char **list)
{
int count = 0;
for (; *list; list++)
count++;
return count;
}
由于非常具体的情况,(1)很容易合并条件和增量和(2)你没有使用正文中的当前项目,它可以转向:
size_t get_size(char **list)
{
int count = 0;
while (*list++)
count++;
return count;
}
for
与while
难题虽然技术上while
和for
循环是等价的,但for
循环更好地表达了迭代习惯方式,因为它使迭代逻辑与代码的其余部分因此也使其更具可重用性,即您可以对列表中的任何其他迭代操作使用具有不同主体的相同for
标头。
for
循环使用不当有许多事情应该被视为气馁:
1)不要从for循环标题修改对象。
for (... ; ...; (*item)++)
...
只要item
是指向实际数据的临时指针,任何与上述模式匹配的代码都会修改目标对象,而不是执行循环逻辑。
2)不要将任何非循环代码与for循环头解耦。
char **item = list;
...
for (; *item; *item++)
count++;
for循环之前的赋值似乎不合适。如果你复制粘贴for循环的标题以在所有列表项上再次迭代,那么由于省略了初始化,列表似乎是空的。
3)不要在for循环标题的增量中执行任何每项操作。
for (char **item = list; *item++, count++)
;
此处count++
根本没有帮助循环,而是执行实际操作(计算一个项目)。如果您复制粘贴for循环的标题并添加了实际正文,count
将被修改。
4)不要对参数使用非描述性,对临时变量使用简单名称。
for (char **var2 = var1; *var2; var2++)
count++;
这两个变量的目的不同,但它们的名称几乎相同,只能用数字来区分。你如何命名它们是一个背景和偏好的问题。
注意:有些人也喜欢与NULL进行显式比较,而不是依赖于指针的布尔值。不过,我不是其中之一。 Stack Exchange似乎突出显示list
作为关键字,但我不认为在C或C ++中有这样的关键字。
答案 2 :(得分:1)
如果你将var2初始化为for循环的第一个参数,我宁愿使用for循环,即
for(char **var2 = var1; *var2; var2++)
因为所有条件(初始,终端,增量)都位于一个地方
我也希望明确地进行测试,即
for(char **var2 = var1; *var2 != NULL; var2++)
因为它使终端条件更加明显。
下一篇:我不会在for循环中放置count++
,因为如果在循环内部没有修改count,那么它是冗余的,可以从var2 - var 1中计算出来。如果在循环内修改了count,它应该可以在一个地方完成。
但我认为这只是一种品味问题。
答案 3 :(得分:1)
可能两者都相同,编译器不应该有任何区别。
答案 4 :(得分:0)
首先,两个循环都是错误的。他们毫无意义。我认为你的意思是以下
int count = 0;
while ( *var1++ ) ++count;
这是我要使用的循环。
或者,如果您希望var1不会被更改,那么
int count = 0;
for ( char **p = var1; *p; ++p ) ++count;
你也可以写
char **p = var1;
while ( *p ) ++p;
int count = p - var1;
答案 5 :(得分:-1)
你最好使循环条件语句更强大和明确,以避免错误和无限循环。哪一个更好取决于你的逻辑和代码,“for”循环更快更容易,但如果你想创建一个需要更多逻辑的循环,那么使用“while”循环。