就地反转''终止的 C 字符串?



我有一些关于反转以null结尾的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 */
}
}
}

很多问题。。。尝试捕获每个问题的答案:

/*是*str=opal还是*str=o,因为指针str的类型是char?*/

*str'o',因为它指向第一个字符

/*char*end和char*end之间有什么区别?现在*end指向蛋白石了吗?*/

char *endchar* end之间没有差异。当你写时,它会变得更棘手

char* a, b;

因为这相当于

char *a, b;

而不是,正如你可能认为的

char *a, *b;

这就是为什么写char *end;更干净的原因。

end现在指向opal——*end就是'o'

if(str){/*如果str不为null?*/

是-测试您没有通过空指针

要测试您没有通过长度为0的字符串,您必须测试*str(在测试str不是NULL之后,否则您会因为"大胆查看*NULL"而得到分段错误)

while(str<end){/*为什么不*str<*end?这是在询问while o<l吗?*/

测试指针-一个向末尾移动,另一个向后移动。当你在中间相遇时,你会停下来;否则你交换两次,就不会有净效果。。。

*str++ = *end; /* what is the difference between *str++ and ++str? does *str++ = l? */

首先将*end的值复制到*str,然后递增str指针。如果你放++str,你先递增,然后使用它。这意味着你把l放在p的位置,而不是o的位置。

编辑对您的代码的一个评论(超越您提出的问题,并回复@chux的评论):当您测试if(str){}时,您确实需要一个else return;语句,因为您实际上是做end--;,然后使用*end。很确定0xFFFFFFFFFFFFFFFF几乎总是一个无效地址。。。

如果您实际上是在测试if(*str!=''),那么您仍然应该返回(空字符串是"不可逆的"——或者更确切地说,它不需要任何东西被认为是可逆的)。

顺便说一句,我更喜欢把条件明确化(就像我刚才做的那样);它不仅更清楚地显示了您的意图,而且如果您使用if(str!='')if(*str != NULL),编译器实际上可能会抱怨,因为您正在比较的类型是不兼容的。这意味着您将拥有更健壮、可读性更强、更有可能实现预期的代码。

因为指针str是char类型,所以*str=opal还是*str=o?

*str取消引用类型为char*的指针,因此您得到的类型是char。该char将是由str所指向的值,该值将是'o'

char*end和char*end之间有什么区别?

什么都没有。

现在*end指向蛋白石了吗?

是的,好吧,结束。end指向与str完全相同的adddress,后者是字符串的开头。*end是一种字符类型,而不是指针。其值将为'o'

如果str不为null?

正确,对指针进行布尔测试是标准测试。如果指针不为null,则其计算结果为"true"值,否则为"false"值。请注意,这与零值不同。C标准允许任何值表示一个空地址。

为什么不*str<终止这是在o<l?

不,它正在比较实际的内存地址。它说循环,而str指向比end更早的字符串部分。您会注意到,在循环过程中,str会增加,而end会减少。因此,最终他们会在同一个字符处相遇(即字符串中间的)。

*str++和++str之间有什么区别?*str++=l吗?

首先应用str++,它递增str并返回其前一个值,然后*一元运算符引用以给出旧位置的字符。是的,第一次,end中的'l'将被分配到字符串的开头(其中str在递增之前用于指向)。tmp用于携带旧字符并将其分配给end。这是一个标准的"交换"操作。

因为指针str是char类型,所以*str=opal还是*str=o?

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之前将值分配给取消引用的变量。

假设reverse是这样调用的:

char str[] = "opal";
reverse(str);

并被分配给内存,例如:

内存地址:100 101 102 103 104内存值:['o']['p']['a']['l']['\0']

关于地址,以下为真:

  1. str + 0 == &str[0] == 100
  2. str + 1 == &str[1] == 101
  3. str + 2 == &str[2] == 102
  4. str + 3 == &str[3] == 103
  5. str + 4 == &str[4] == 104

关于值,以下是正确的:

  1. *(str + 0) == str[0] == 'o'
  2. *(str + 1) == str[1] == 'p'
  3. *(str + 2) == str[2] == 'a'
  4. *(str + 3) == str[3] == 'l'
  5. *(str + 4) == str[4] == ''

关于NULL,当指针未初始化,即未指向有效内存时,应为其分配NULL的值,在大多数情况下,该值为地址0。考虑以下内容:

char *str = NULL;
reverse(str);

当评估以下表达式时:

if(str)

它将评估为FALSE。在reverse中,它应该(您应该修复它)立即return,因为使用地址为NULL的指针会导致不确定的行为,例如分段错误。

当地址为NULL时,将str的地址分配给end,然后递减:

--end;

将导致不确定的行为。

执行*str = opal还是执行*str = 'o',因为指针str的类型是char

两者兼而有之。我知道这很令人困惑,但事情是这样的:在C中,指针可以用两种方式解释——要么是字面上的,即指向单个项的指针(在本例中为char),要么是指向同一类型项序列开头的指针。在后面的情况下,将定义序列的末尾。有三种方法可以知道序列的结束位置——明确地知道长度,知道结束指针,或者在序列的末尾放置一个"终止符"项。在C字符串的情况下,使用一个称为"空终止符"的特殊字符''来终止序列。

char* endchar *end之间有什么区别?*end现在指向蛋白石吗?

绝对没有区别——它们都指向同一个地方。星号的位置无关紧要。

如果str不是null

纠正

end指针指向'l'现在是

当然!

为什么不*str < *end?这是在问while o < l吗?

您比较的是内存中的位置,而不是它们指向的字符。这是要求指针不要相互"交叉",因为两者从字符串的两端都指向中心。

tmp = o

在第一次迭代中为。在第二次迭代中,它指向'p'

*str++++str之间有什么区别?*str++='l'吗?

++str表达式递增指针的值,并在递增后计算为指针的值*str++表达式递增指针的值,并计算为递增前指针指向的字符的值。

最新更新