使用 n[c-'0'] 的真正用途是什么?
What's the real use of using n[c-'0']?
我是一个C新手,我遇到了这样的代码:
int n[10];
if(c>='0' && c<='9')
++n[c-'0']
在if
循环中,为什么我们必须在0
周围使用单引号,它的用途是什么,为什么我们不能直接将0
定义为整数?在第二行代码++n[c-'0']
中,像这样使用数组有什么用,在某种意义上为什么我们需要从数组索引中的c
中减去0
(再次说明为什么在这种情况下使用单引号?)?
如果我喜欢这个n[c-'0']
,索引操作(c-'0'
)的结果将是一个字符或整数?
有人能告诉我,这种数组的真正用途是什么,缺点是什么?
提前感谢。
在C语言中,'0'
是一个整数,其值表示数字0作为字符,而不是值0,它将是空字符。其他答案省略了这一点,但重要的是要注意C语言强制要求十进制数字具有连续值,因此,如果c
是一个数字,c-'0'
是该数字的数值,即
'0'-'0' = 0
'1'-'0' = 1
'2'-'0' = 2
.
.
.
'9'-'0' = 9
c
(可能)是char
,它也具有整数表示,并且在C中可以隐式转换。'0'
是字符0,数字字符的一个方便的特性是它们按照整数表示顺序排列。
那么,现在您知道每个字符都有整数表示,并且数字字符是按顺序排列的,您可以使用简单的减法将字符转换为整数表示。
'0' - '0' == 0
'1' - '0' == 1
'2' - '0' == 2
/* and so on and so forth */
因此,如果您想计算字符串中数字的出现次数,您可以使用它:
int n[10]; /* 10 digits */
n['0' - '0'] /* where we store the counts for the character 0, aka n[0] */
n['1' - '0'] /* where we store the counts for the character 1, aka n[1] */
你可能已经知道,计算机把字符表示为数字。C标准要求这种表示必须确保数字必须彼此紧跟着。如果n是'0'
的代码,那么n + 9就是'9'
的代码。对于ASCII,这些值分别是48和57。
你发布的代码示例试图是编码不可知的,而不是对48或57检查,它使用'0'
作为一个可移植的常数。
看一下ASCII表,因为它本身可能已经很好地解释了它。字符'0'的十进制表示为48,'1'为49,等等。大多数(如果不是所有的话)编译器都遵循这个转换表。
通过减去'0'(很可能是数字48),您实际上将变量c
的字符表示转换为数字表示。
edit:正如在注释中提到的,我应该指出'0'或'9'的数字表示不一定遵循ASCII转换表(尽管我相信所有通用编译器都遵循)。这是一个技术细节,属于ANSI C规范的讨论,而不是针对学习该语言的人的回答。
如果Ant碰巧写了int number = '0';
,并且想知道为什么它存储数字48,那是因为他的编译器遵循ASCII转换。这个对于一个学习c基础知识的人来说既有用又有帮助。如果有哪个编译器不这样做,那就不是什么罕见的事情了,我很乐意把它留在那里,但我认为更多的时候,比起有用的回复,SO更看重迂腐。
也就是说,不使用实际的数字表示仍然是一件好事。也就是说,总是更喜欢写"0"而不是"48"。但很高兴知道为什么"0"最有可能由数字48表示。
'0'
和'9'
属于int
类型。它们的值分别是48和57(因为48和57是字符'0'
和'9'
的ASCII值)。
所以你可能在n
中保存一个数组来计数数字。
所以这个表达式(如果你在c
上存储数字字符):
++n[c-'0'];
的意思是:
- 取n的位置号
c-'0'
(c
上有一个数字) - 将该位置增加1。
所以n
将是:
n[0] = x; // count of 0 characters
n[1] = x; // count of 1 characters
n[2] = x; // count of 2 characters
n[3] = x; // count of 3 characters
n[4] = x; // count of 4 characters
n[5] = x; // count of 5 characters
n[6] = x; // count of 6 characters
n[7] = x; // count of 7 characters
n[8] = x; // count of 8 characters
n[9] = x; // count of 9 characters
例如,假设c
等于字符2
。2
的ascii值为50
。所以n[50-48]
变成了n[2]
。因此,您最终使用数组n
的第三个元素来存储2
字符数。
首先,if
不是一个循环,它是一个语句。只需要通过一次代码。
这意味着第一行可以读取if c is a digit
,第二行将ascii数字转换为整数(并增加n数组中的元素以计数该数字)。
脱离上下文,很难说为什么作者会这样做。
代码所做的是将字符'0'
循环到'9'
,可能是将它们与某些用户输入进行比较。在循环体中,为了索引数组n
,这些字符被映射到整数0..9
。
C中的字符在进行算术运算时可以表现得像整数,通过将其转换为ASCII整数表示。第一次循环时,c
为0
, '0' - '0'
为整型0
,与'0'
的整型值无关。也就是说,x - x
总是等于0;在这种情况下,x
的实际值并不重要。
考虑到这一点,并且ASCII值是顺序的,从0
递增到9
,您可以告诉第二次通过循环时,c
将是'1'
, '1' - '0'
是整数1
,以此类推。
'0'
表示一个字符值,它可以无声地转换为整数,结果(通常)是字符'0'
的ASCII值(碰巧是48)。if
条件验证c
是(可转换为)一个包含数字的字符值。这是可能的,因为数字0到9在ASCII图中分别由48到57的连续值表示。如果从任意数字字符的ASCII值中减去'0'
的ASCII值(即48),则得到该数字的数值(从0到9)。
所以上面的代码索引到一个计数器数组,可能是为了计算某些文本中每个数字的出现次数。
因为c
是字符而不是整数
'0'的ASCII值是48,所以'0'在n[c]
语句中将是索引48,程序员希望'0'是索引0,因为n
被定义为n[10]
,所以ASCII值通过减去'0'的代码转换为其等效的整数,因此:'0' - '0' = 0
, '1' - '0' = 1
等。从"0"到"9"的ASCII码是48到57,所以转换是合理的。
至于为什么,我猜有人在计算数字"0"到"9"在某些文本中的频率。
允许使用char
作为数组的索引。例如,您可以定义字符串"012345"
(可能从外部文件读取),并计算每个字符c-'0'
,这将分别给出整数0
、1
、2
、3
、4
和5
。
这段(可怕的)代码映射了数字0的ASCII值。从9到0的索引。'0'
的类型是数字类型char
。'0'
的数值通常为48
。从表示数字的char
中减去48
将为您提供char
的"值"
这是将某物的ascii值转换为其数字的一种方法。在C语言中,字符'0'的ascii值是48。所以减去:
'0' - '0' = 0
'1' - '0' = 1
...
c - '0' = <whatever the decimal number of c is>
方便的是,ASCII十进制数的增量是连续的,否则这个技巧将不起作用。换句话说,c
必须是'0'之一。"9"才行。这解释了限制:
if(c>='0' && c<='9')
-'0'从给定的个位数整数中减去0(48)的ASCII值(应该只包含1位数字),从'0'到'9'的数字按顺序存储在ASCII码中,因此从给定的个位数整数中减去0的ASCII值将得到整数本身的数值。例如:- '4'的ascii值是52减去'0'的ascii值是48从52将给我们的数值4等于给定的整数,因此我们使用减法,而不是+'0'的加法,也减法或任何其他值的加法也不会导致给定整数的相同数值。
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 使用libcurl提交批量url的正确BING Api POST url是什么
- 使用rdtsc进行基准测试的缺点是什么
- 是什么导致了这种使用三进制而不是短整型的有符号int到无符号int转换
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++:使用方法调用析构函数的顺序是什么?
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- C++关于指针和使用函数将它们启动到堆的行为究竟是什么?
- 使用共享指针时,从共享指针本身释放内存的机制是什么
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- 在nodejs中使用本机代码的最佳方法是什么?
- 在使用包含冒号的类似函数的宏时,是什么导致了这种编译器差异?
- 使用动态链接加载程序 <dlfcn.h> 而不是直接函数调用的目的是什么?
- 在模板参数中使用 {} 在 type_trait{} 中时,其作用是什么<T>?
- 解析此 json 的正确方法是什么?使用 ArduinoJson
- 该C 代码的C#等效是什么(使用INPTR)
- 在c++中,最快的方法是什么(使用OpenMP)