【问题标题】:C: Why does C need the memory address of a char in order to convert it to an int? [closed]C:为什么 C 需要 char 的内存地址才能将其转换为 int? [关闭]
【发布时间】:2015-05-06 21:17:25
【问题描述】:

来自 Python,我会简单地使用 type() 来找出对象的类型,C,缺乏自省,迫使我更好地掌握它的数据类型、它们的相关性和指针,然后再继续了解更多进阶话题。 这是一件好事。所以我有以下一段代码,我将通过各种方式对其进行调整并尝试理解产生的行为:

int main(int argc, char *argv[])
{
    int i = 0;
    for(i = 0; argv[1][i] != '\0'; i++) {
         printf("%d\n", argv[1][i]);
         char letter = argv[1][i];

    switch(letter) {
        case 2:
            printf("%d: 2\n", i);
            break;

如果我运行它并将数字 2 作为单个参数传递,则不会发生任何事情。我的理解是,因为我已将 argv1[i] 定义为 char,将其与 2(一个 int)进行比较将返回 false,因此不会调用代码。事实上,如果我将大小写从 2 更改为“2”,代码确实会被调用。有道理,但它引出了我的第一个问题:

Q1. 我在很多地方读到过,对于 C,字符和整数本质上是一回事。 那么为什么 C 不“知道”作为参数传递的 2 应该被解释为整数而不是字符串?毕竟,C 允许我使用 %d 字符串字符格式化程序。

如果我随后将变量 letter 的类型从 char 更改为 int:

int letter = argv[1][i];

...我仍然得到与第一个变体相同的行为(即没有发生任何事情),即使现在我显然正在将 int 与 case 语句中的 int 进行比较。这使我推测,尽管我现在将 letter 定义为 int,但 C 仍在命令行上将其作为 char 读取,并且仅将其称为 int 不足以改变它从后续程序流程的角度来看类型。

第二季度。以上推理正确吗?

所以现在我想如果我使用 atoi() 将字母的类型更改为 int,那么一切都会好起来的。所以:

int letter = atoi(argv[1][i]);

当我现在尝试编译时,我得到:

Switch.c:14:27: warning: incompatible integer to pointer conversion passing
      'char' to parameter of type 'const char *'; take the address with &
      [-Wint-conversion]
        int letter = atoi(argv[1][i]);
                          ^~~~~~~~~~
                          &
/usr/include/stdlib.h:132:23: note: passing argument to parameter here
int      atoi(const char *);

然后我查看 atoi() 的文档,发现它只能用于转换字符串(更准确地说,是 const char *),而不是字符。我会认为,因为 char * 只是一个字符序列,所以 atoi() 可以同时使用这两个字符。显然,对于 char 没有等价的 atoi(),而只有解决方法,例如描述的 here

无论如何,我决定接受警告的说明,并在值之前放置一个 & 号(知道这意味着一个内存地址,但还不知道为什么建议它)。所以:

int letter = atoi(&argv[1][i]);

当我这样做时,它会编译。现在这个最终形式的程序 - 将字母定义为 int,case 语句与 int 进行比较,并且 atoi 被传递地址而不是 argv[1][i] 的值 - 成功运行。

但我不知道为什么,所以我把它剥离出来,通过打印argv[1][i]&argv[1][i] 的值来测试它们。我观察到程序只有在我使用 %s 字符串格式化程序来打印 &argv[1][i] 时才能编译,因为它告诉我 &argv[1][i] 是一个字符 *。

第三季度。为什么&argv[1][i],内存中的地址,char *?

在我的打印输出中,我观察到&argv[1][i]argv[1][i] 的值是相同的,即:2。所以:

第四季度。为什么编译器不允许我使用argv[1][i],如果它的值与&argv[1][i] 的值没有区别?

Q5。每当我在 C 程序中打印内存地址时,它总是一个长数字,例如 1246377222。为什么在这种情况下内存地址 == 值?

毫无疑问,会有人反对这个庞大的帖子应该分成不同的帖子和不同的问题,但我认为反复试验的流程以及您提供的答案不仅会帮助我,还会帮助其他人了解 C 的这些方面。也可以随意为帖子建议一个更好的标题。

非常感谢。

【问题讨论】:

  • 您要求的是 C 编程课程的整个介绍部分。一个问题相当多。
  • atoi() 存在是有原因的 - 请参阅 here
  • 是的,如果只允许我回答其中一个问题,那就是 Q5。我邀请你阐明一些观点。非常感谢。
  • 您一次只能问一个问题。我试图回答标题中的问题。
  • 这里有很多好问题!

标签: c pointers type-conversion pass-by-reference memory-address


【解决方案1】:

你的误解是2 != '2'。它们都有整数值,但这些值彼此不同。 '2' 的 ascii 值不等于 2 它等于 50。这意味着 int a = '2'; 导致 a 评估为 50。将整数字符转换为数值的标准方法是写入 int a = '2' - '0'; 这将导致 a 计算为 2

argvchar * 的数组。这意味着argv[j][i] 是一个字符,&argv[j][i] 是一个char *,它是位于argv[j][i] 的字符的地址。这意味着atoi(&argv[j][i]) 将编译,但我不确定它是否符合您的预期,因为它会尝试将从argv[j][i] 开始的整个字符串转换为一个数字,而不仅仅是argv[j][i] 处的特定字符。

【讨论】:

    【解决方案2】:

    Q1:charint 只是在它们都是(有符号 - 通常)整数的意义上“相同”。有多个不同之处,例如char(通常)为 1 个字节长,而int(通常)至少为 4 个字节长。

    Q2:您的推理是错误的,因为您将字母 '2'(即 50)的 ASCII 代码与数字 2(在 ASCII 中没有视觉表示)进行了比较。

    Q3:你的调试出错了——&argv[1][i]argv[1]字符串中i-th字符的地址。所以本质上这是一个指针。在您的调试器中,您可能看到了“指向”的字符。

    Q4:见上文 - argv[1][i]'2',而 &argv[1][i] 是内存中的地址,可以在其中找到此 '2'

    Q5:您可能在调试时犯了一个错误 - 请参阅 Q3 的答案。

    【讨论】:

    • 请注意,char 可以签名也可以不签名。
    【解决方案3】:

    C 中的字符串是带有空终止符的字符序列。它总是由地址(第一个字符的)引用,因为它的长度是可变的。

    【讨论】:

    • 好的,但是(i)为什么它必须总是被地址引用,因为它的长度是可变的?你能向我解释为什么一个需要另一个吗?并且 (ii) 在我的示例中, argv[1][i] 是一个字符,而不是一个字符串。
    • 整数、字符和浮点数都可以放入寄存器中,因此可以独立于内存中的某个位置存在,并且通常可以通过一条 cpu 指令来移动。这并不意味着该语言不能具有按值引用的字符串类型,但 C 倾向于与硬件保持接近。对,argv[1][i] 是一个字符,这就是为什么你不能将它传递给 atoi。
    【解决方案4】:

    第四季度。为什么编译器不允许我使用 argv[1][i],如果它的值与 &argv[1][i] 的值没有区别?

    他们不一样

    &argv[1][i] 是一个指向内存位置的指针

    argv[1][i] 是那个位置的字符的值

    就是这样

    printf("%s", &argv[1][i]); // Prints the c-string at memory position
    printf("%c", argv[1][i]); // Prints the char
    

    我假设当您说“打印”时,您的意思是 printf() 函数。

    【讨论】:

    • 对,显然我还没有掌握指针的概念,您的回答可能有助于澄清事情。内存位置如何同时保存 c-string 和 char?
    • 内存位置包含一个字符。但是 c 字符串是指向以 '/0' (空确定符)结尾的字符“数组”的指针。在这种情况下没有区别,因为字符串只有一个字符长。
    【解决方案5】:

    对于Q5,正如你所说的你来自Python,在C Python中实现的id作为变量的地址。即使在 Python 中,数值变量的 id 也不是变量的值。

    【讨论】:

      猜你喜欢
      • 2020-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多