【问题标题】:What's the meaning of subtracting 'a' from elements of char array从char数组的元素中减去'a'是什么意思
【发布时间】:2019-03-18 09:48:26
【问题描述】:
  1. a[s1[i] - 'a']和是什么意思
  2. int a[26] = {0}(我不确定,但它是否用于将数组的每个元素初始化为 0 值)
int main()
{
    char s1[10010], s2[10010];
    cin >> s1 >> s2;
    int a[26] = {0};
    for(int i = 0; i < strlen(s1); i++)
        a[s1[i]-'a']++;
    for(int i = 0; i < strlen(s2); i++)
        a[s2[i]-'a']--;
    long long int ans = 0;
    for(int i = 0; i < 26; i++)
        ans += abs(a[i]);
    cout << ans << endl;
    return 0;
    
}

【问题讨论】:

  • ASCII_Table 这将帮助您更好地了解其他答案所引用/基于的内容。
  • 此代码缺少注释,例如输入必须为小写 Basic Latin 字母。并且,它应该使用与用于执行字符编码的编译器相同的字符编码(或兼容)与输入一起运行。 (-fexec-charset/execution-charset)。 [如果这些编码都是 ASCII 兼容的,它就可以工作。所以,即使不是,人们也会说 ASCII。]

标签: c++ arrays char


【解决方案1】:

通常,表达式(cchar

c - 'a'

用于获取 ['a', 'z'] 范围内的字符(大小为 26,因为它源自英文字母表)并计算该字母的索引(例如 @987654328 @是0'b'1等)。


同样,当你看到:

c - '0'

它通常用于计算 [0, 9] 范围内字符的“数字”值,例如'5'(字符)映射到5(整数)。

【讨论】:

  • Thnq 的答案。被怀疑清除!!
  • 这两个例子之间有一个关键的区别。语言定义需要第二个工作,但它不需要第一个工作。有些字符编码第一个不起作用。
  • @PeteBecker 好点,谢谢皮特! [lex.charset]p3,不是吗?不过,对于 2018 年的大多数环境,特别是对于初学者来说,可以说它只是有效。出于好奇,您是否知道任何仍在使用的系统默认不使用最常见的系统之一(ASCII、8859、Unicode...)?更糟糕的是,使用c - 'a' 的系统无法工作?
  • IBM 大型机使用EBCDIC。请注意与字母对应的值中的空白。
  • 顺便说一句,我不同意告诉初学者“这会起作用”,因为它几乎适用于所有系统。这导致if ('a' &lt;= ch &amp;&amp; ch &lt;= 'z'),当有一个便携式解决方案时:if (islower(static_cast&lt;unsigned char&gt;(ch)))。诚然,将字母转换为索引更难,但只能在意识到它不可移植的情况下完成。
【解决方案2】:

1) a 是一个包含 26 个条目的数组,每个条目对应一个字母表。但是字符 'a' 的值不是 0,因此要获取数组的第 n 个字母,您可以使用 s1[i]-'a'

2) int a[26] = {0} 在数组的第一个元素中放置一个零,然后默认初始化其余元素(对于整数也意味着零,所以请注意它不会像你认为的那样做),我' d 说改用std::vector&lt;int&gt; a(26, 0);。您仍然可以使用 int a[26] = {} 将其初始化为 0s 并明确表示您了解 {0} 只会将数组的第一个元素而不是整个数组初始化为此值:http://www.cplusplus.com/doc/tutorial/arrays/

当然,这个程序只有在只输入小写字母时才有效。如果输入任何其他内容,则程序的行为未定义,它可能会崩溃。

【讨论】:

  • 也可以使用std::array&lt;int, 16&gt;,然后使用fill将其初始化为0。
  • 确实,还不够清楚。还添加了有关默认初始化的说明。
  • 没有。它仍然是错误的。两种形式的零都初始化整个数组。
  • 我就是这么说的。你读过我的编辑吗?首先用 0 初始化,然后为其他整数执行默认初始化(对于整数为 0),但我添加了一个警告以指示 {0} 不会用 0 初始化整个数组,因为有一个零 {} 但因为它的默认构造为 0。放置 {1} 不会用 1 填充数组。
【解决方案3】:

a[s1[i] - 'a'] 的值s1[i] 减去'a' 的ascii 值将是a[] 的索引。确保s1[i]大于字符的ascii值。

关于下面的,第一个元素将被设置为 0

    int a[26] = {0};

【讨论】:

    【解决方案4】:
    int a[26] = {0};
    

    这只是用零初始化名为“a”的数组中的所有项目。 当使用大括号初始化语法初始化内置类型数组时,可能会发生两种类型的初始化。如果初始值设定项少于数组大小,则前 N 个元素使用相应的值进行初始化,其余元素使用默认构造函数进行初始化。对于内置类型,默认构造函数进行零初始化。

    a[s1[i] - 'a']
    

    在内部,字符是简单的十进制数字。每个字符都有与之关联的唯一代码。 (见https://en.m.wikipedia.org/wiki/ASCII) 如果数组“s1”包含小写拉丁符号,则s[i] 在位置“i”处采用符号。然后我们从符号s1[i] 的代码中减去符号'a' 的代码,得到符号s1[i] 的字母编号(从零开始计数)。例如:'a'-'a' = 0'b' - 'a' = 1 然后我们使用计算出的“数字”来访问数组“a”中位置“数字”的元素

    【讨论】:

    • ASCII 很常见,但不是一种保证编码。 OP中的代码只需要小写字母顺序编码的编码。
    • @StoryTeller 嗯,是的,你是对的。但最常用的编码将拉丁字符映射到与 ascii 中完全相同的代码
    • @Matthieu Brucher,看看en.cppreference.com/w/c/language/array_initialization。语法看起来具有误导性,但确实如此。
    • 对不起,删除了我的评论,这是错误的。您的解释仍然不清楚0s 的来源。
    【解决方案5】:

    这意味着有人在做假设。您可以使用表示整数的字符来执行此操作:c - '0' 将为您提供与字符 '0''1'、'2'、...'9'相对应的整数值。这是由语言定义保证的。任何其他字符值都没有这样的保证。所以这段代码猜测c - 'a' 将产生一个数值,该数值以某种方式反映c 所代表的字符。在最常见的字符编码中它可以工作;在迄今为止使用最广泛的 ASCII 中,如果 c 表示小写字母,则 c - 'a''a' 映射为 0,'b' 映射为 1,...,'z' 映射为 25。但是有些字符表示不正确。

    但请注意,此代码不执行任何输入验证。如果有人输入了“Z”、“0”或“;” (仅举几例),生成的索引将超出数组边界,并且可能会发生不好的事情。

    对于int a[26] = {0};,这称为聚合初始化。数组是一个聚合,也就是说,它包含多个值。 {something} 形式的初始化器将 something 复制到聚合中的第一个元素,并将其余元素设置为 0。因此 int a[26] = {0}; 将数组 a 的所有 26 个元素设置为 0。

    聚合初始化中的初始值设定项不必为 0。int a[26] = {3}; 会将第一个元素 (a[0]) 设置为 3,将数组的其余元素设置为 0。

    聚合初始化不限于单个值。您可以拥有任意数量的值,以逗号分隔。所以int a[26] = { 1, 2, 3 }; 会将前三个元素分别设置为 1、2 和 3,其余的都设置为 0。如果初始值设定项的数量多于元素数量,则忽略多余的元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-22
      • 2021-02-01
      • 1970-01-01
      • 2019-11-26
      • 1970-01-01
      • 2020-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多