我有一些关于反转空终止C字符串的概念性问题,以及关于指针性质的澄清问题。
输入可能是
char arr[] = "opal";
和代码:
void reverse(char *str) { /* does *str = opal or does *str = o since the pointer str is type char? */
char* end = str; /* what is the difference between char* end and char *end? and is *end pointing to opal now? */
char tmp;
if (str) { /* if str isn't null? */
while (*end)
++end;
}
--end; /* end pointer points to l now */
while (str < end) { /* why not *str < *end? is this asking while o < l? */
tmp = *str; /* tmp = o */
*str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */
*end-- = tmp; /* *end points to o */
}
}
}
答案 0 :(得分:9)
很多问题......试图捕捉每个问题的答案:
/ *做* str = opal或者* str = o,因为指针str是char类型? * /
*str
为'o'
,因为它指向第一个字符
/ * char * end和char * end有什么区别?现在是*结束指向蛋白石? * /
char *end
和char* end
之间没有区别。当你写
char* a, b;
因为这相当于
char *a, b;
而不是,你可能会认为
char *a, *b;
这就是为什么写char *end;
更清晰。
end
现在指向opal
- *end
为'o'
。
if(str){/ *如果str不为空? * /
是 - 测试你没有通过NULL指针
为了测试你没有传递一个长度为0的字符串,你必须测试*str
(在测试str
不是NULL之后,否则你会得到一个“daring to”的分段错误看看* NULL“)
while(str&lt; end){/ *为什么不* str&lt; *结束?这是在问o&lt; L· * /
测试指针 - 一个正在向末端移动,另一个正在向后移动。当你在中间相遇时,你会停下来;否则你做两次交换,并且没有净效果......
*str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */
首先将*end
的值复制到*str
,然后递增str
指针。如果你放++str
,先增加,然后再使用它。这意味着您将l
代替p
而不是代替o
。
编辑对您的代码进行一次批评(超出您提出的问题,并回复@chux的评论):当您测试if(str){}
时,您确实需要{{1} }}语句,因为您实际执行else return;
然后使用end--;
。很确定*end
几乎总是无效的地址......
如果您实际上正在测试0xFFFFFFFFFFFFFFFF
,那么您仍然应该返回(空字符串是“不可逆转的” - 或者更确切地说,它不需要被视为反转)。
顺便说一句,我更喜欢明确表达这个条件(就像我刚才那样);它不仅更清楚地表明您的意图,而且如果您执行if(*str!='\0')
或if(str!='\0')
,编译器可能会抱怨,因为您要比较的类型不兼容。这意味着您将拥有更强大,更易读且更有可能实现预期目标的代码。
答案 1 :(得分:2)
是* str = opal还是* str = o因为指针str是char类型?
str
是指向opal
的第一个元素的指针,即它是指向第一个字母o
的指针。因此,*s
表示您取消引用s
(第一个地址),因此它是'o'
。
char * end和char * end有什么区别?现在是*结束指向蛋白石?
没有区别。不,它是end
指向opal
,即它现在的第一个元素。
如果str不为null?
是。
结束指针指向l now
是。它现在指向该词的最后一个字母。
* str ++和++ str有什么区别? * str ++ = l?
*str++
表示str
在取消引用str
指向的值后会递增。 ++str
只是str
的预增量
*str++ =
在递增str
之前将值分配给解除引用的变量。
答案 2 :(得分:2)
确实* str = opal或者* str = o,因为指针str是char?
类型
*str
取消引用类型为char*
的指针,因此您获得的类型为char
。 char
将是str
指向的值,'o'
。
char * end和char * end之间有什么区别?
没有
现在是*结束指向蛋白石吗?
是的,好吧,关闭。 end
指向与str
完全相同的地址,这是您的字符串的开头。 *end
是字符类型,而不是指针。其值为'o'
。
如果str不为空?
正确,对指针进行布尔测试是标准测试。如果指针不为null,则计算为“true”值,否则为“false”。请注意,这与零值不同。 C标准允许任何值表示空地址。
为什么不* str&lt; *结束?这是在问o&lt;升?
不,它正在比较实际的内存地址。它表示循环,而str
指向字符串的早期部分而不是end
。您会注意到,在循环过程中,str
会增加,end
会减少。所以最终他们会相互传递或者以相同的角色相遇(即中间的字符串)。
首先应用* str ++和++ str有什么区别? * str ++ = l?
str++
,它会递增str
并返回其先前的值,然后是*
一元运算符,以便在该旧位置给出字符。是的,第一次,来自'l'
的{{1}}将被分配到字符串的开头(end
用于在增加之前指向它)。 str
用于携带旧字符并将其分配给tmp
。这是标准的“交换”操作。
答案 3 :(得分:2)
假设reverse
被调用如下:
char str[] = "opal";
reverse(str);
并且被分配给内存,例如,像这样:
Memory Address: 100 101 102 103 104 Memory Value: ['o'] ['p'] ['a'] ['l'] ['\0']
关于地址,以下内容属实:
str + 0 == &str[0] == 100
str + 1 == &str[1] == 101
str + 2 == &str[2] == 102
str + 3 == &str[3] == 103
str + 4 == &str[4] == 104
以下关于值的说法是正确的:
*(str + 0) == str[0] == 'o'
*(str + 1) == str[1] == 'p'
*(str + 2) == str[2] == 'a'
*(str + 3) == str[3] == 'l'
*(str + 4) == str[4] == '\0'
关于NULL
,当指针未初始化时,即未指向有效内存时,应为其分配NULL
的值,在大多数情况下,该值为地址0.考虑以下内容:
char *str = NULL;
reverse(str);
评估以下表达式时:
if(str)
它将评估为FALSE
。在reverse
内,它应该(您应该立即修复)return
因为使用地址为NULL
的指针会导致未确定的行为,例如分段错误。
当地址为str
时,将end
的地址分配给NULL
,然后将其递减:
--end;
会导致行为不确定。
答案 4 :(得分:1)
是
*str = opal
还是*str = 'o'
,因为指针str
的类型为char
?
两者都是。我知道这很令人困惑,但这是正在发生的事情:在C中,指针可以用两种方式解释 - 字面上,即作为指向单个项目的指针(在这种情况下为char
)或作为指针一系列相同类型的项目的开头。在后一种情况下,将定义序列的结尾。有三种方法可以知道序列的结束位置 - 明确知道长度,知道结束指针,或者在序列的末尾放置一个“终止符”项。对于C字符串,使用名为“null terminator”的特殊字符'\0'
来终止序列。
char* end
和char *end
之间有什么区别?现在是*end
指向蛋白石吗?
绝对没有区别 - 他们都指向同一个地方。星号的位置无关紧要。
如果
str
不是null
?
正确
end
指针指向'l'
现在
绝对!
为什么不
*str < *end
?这问while o < l
?
您正在比较内存中的位置,而不是它们指向的字符。这要求指针不要相互“交叉”,因为这两个指针从字符串的两端走向中心。
tmp = o
在第一次迭代中,它是。在第二次迭代中,它指向'p'
*str++
和++str
之间有什么区别?是*str++
='l'
?
++str
表达式增加指针的值,并在增量后计算指针的值; *str++
表达式增加指针的值,并计算指针在增量之前指向的字符的值。