【问题标题】:Anagram char arrays字谜字符数组
【发布时间】:2021-02-14 06:15:14
【问题描述】:

所以我的 C++ 书中有这个算法

int anagrams(char *x, char *y) {
  char *p;
  if (!*x && !*y) return 1;
  p = strchr(y, *x);
  if (!p) return 0;
  *p = NULL;
  strcat(y, p + 1);
  return anagrams(x + 1, y)
}

它取 x 第一个元素,验证 y 是否有它,如果 y 有它,则将其删除。我真的不明白。 因此,strchr 返回一个指向 x 在 y 中出现的位置的指针。之后,我就不太明白了。顺便说一句

char a[] = "children" ;
char *p = strchr(a, 'i') ;
*p = NULL";

为什么'h'之后的一切都消失了? P 指向“i”,那么“i”不应该消失吗? 谢谢! (我还是个初学者)

【问题讨论】:

  • 你确定这是一本 C++ 书吗?代码看起来更像纯 C。(这并不意味着它也不能用 C++ 编译,而是应该以不同的方式教授惯用的 C++ 代码。)仅供参考:Kate Gregory "Stop teaching C" ;-)
  • 当然,我的错,我的书是c/c++
  • 对于您第一次公开的 sn-p,请提供一个如何调用它的示例。更好的是制作minimal reproducible example

标签: c++ string pointers recursion char


【解决方案1】:

关于为什么'h'之后的一切都消失了?

char a[] = "children" ;
char *p = strchr(a, 'i') ;
*p = NULL";
  1. 有一个错字:应该是*p = NULL;(双引号"是错误的。)

  2. p 的类型为 char*。应用取消引用运算符* 会产生指针类型。因此,表达式 *p 的类型为char。 (请不要将此与声明char* 类型的变量p声明 char *p 混淆。)NULL 旨在表示一个空指针。 (在 C 中,它可能被定义为 #define NULL (void*)0。在 C++ 中,nullptr 应该优于 NULL。)将空指针分配给 char 是……令人困惑,但 C 编译器(以及 C++编译器)可能会将其隐式转换回普通的0

    我用gcc -std=c11g++ -std=c++17 编译了这个。在这两种情况下,编译器都会发出警告,但会提供可执行的二进制文件:

    • C: Live Demo on coliru
      输出:
      warning: assignment to 'char' from 'void *' makes integer from pointer without a cast [-Wint-conversion]
        *p = NULL;
      
    • C++: Live Demo on coliru
      输出:
      warning: converting to non-pointer type 'char' from NULL [-Wconversion-null]
        *p = NULL;
      

    所以,应该是*p = 0;,或者更清楚的是*p = '\0';,这在语义上是相同的,但更清楚地暴露了意图。

考虑到这一点,固定版本是:

char a[] = "children" ;
char *p = strchr(a, 'i') ;
*p = '\0';

它用\0 覆盖带有i 的元素,这是C 字符串中的字符串终止符。

char a[] 以前是:

{ 'c', 'h', 'i', 'l', 'd', 'r', 'e', 'n', '\0' }

在这个分配之后变成

{ 'c', 'h', '\0', 'l', 'd', 'r', 'e', 'n', '\0' }

因此,它仍然具有相同的长度,但将它与 C 字符串函数一起使用(例如 printf("%s", a);)将考虑第一个找到的字符串终止符。 因此,它只会打印ch

演示演示:

#include <cstring>
#include <cstdio>
#include <iomanip>
#include <iostream>

int main()
{
  char a[] = "children" ;
  char *p = strchr(a, 'i') ;
  *p = '\0';
  // printing a c string
  printf("a[]: '%s'\n", a);
  // print a[] element wise
  std::cout << "a[]: {";
  const char *sep = " ";
  for (char c : a) {
    std::cout << sep << '\'';
    if (c >= ' ' && c < '\x7f') std::cout << c;
    else std::cout << '\\' << std::oct << (unsigned)(unsigned char)c << std::dec;
    std::cout << '\'';
    sep = ", ";
  }
  std::cout << " }\n";
}

输出:

a[]: 'ch'
a[]: { 'c', 'h', '\0', 'l', 'd', 'r', 'e', 'n', '\0' }

Live Demo on coliru


关于 OPs C/C++ 书籍的注释:

事实上,C++ 语言是从现有的 C 语言演变而来的。C 和 C++ 仍然相互关联。例如。 C++标准库采用了部分C标准库。

不过,这是两种独立的语言,有各自的标准。

  • 有些 C 语句也适用于 C++。
  • C 中的某些东西在 C++ 中的工作方式略有不同。
  • C 中有些东西在 C++ 中不起作用,反之亦然。

最后的例子:

  • auto是C中有效的存储类。在C++中,这个含义从C++11开始就失效了,关键字有了新的语义:placeholder type specifier
  • Variable Length Arrays 是 C99 标准(和更高版本)的可选功能,但不是任何 C++ 标准的可选功能。一些编译器(例如g++)支持它作为 C++ 中的专有扩展。
  • Type Punning with union 在某种程度上被 C 标准合法化,但被 C++ 标准禁止。
  • 当然,C++ 引入了各种新关键字(具有新语义),例如classtemplate 在 C 中不可用,将被解释为普通标识符。

一个(诚然有点做作的)示例表明相同的源代码可能导致 C 与 C++ 中的不同语义:

  auto a = 'a';
  printf("sizeof a: %d\n", (int)sizeof a);

在 C11 中:

#include <string.h>
#include <stdio.h>

int main()
{
  auto a = 'a';
  printf("sizeof a: %d\n", (int)sizeof a);
}

输出:

sizeof a: 4

Live Demo on coliru

auto 是存储类。 auto a 中缺少一个类型。 C 编译器默认为int

在 C++11 中:

#include <cstring>
#include <cstdio>

using std::printf; // pull printf() into global scope

int main()
{
  auto a = 'a';
  printf("sizeof a: %d\n", (int)sizeof a);
}

输出:

sizeof a: 1

Live Demo on coliru

auto 从其初始化中确定a 的类型。在 C++ 中,字符常量的类型为 char(与 C 相反,它们的类型为 int)。

【讨论】:

    猜你喜欢
    • 2014-10-24
    • 2021-09-16
    • 2011-11-30
    • 2012-03-27
    • 2012-01-22
    • 2017-01-16
    • 2021-11-19
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多