鱼C论坛

 找回密码
 立即注册
楼主: 11063216906

[已解决]浮点数存取问题

[复制链接]
 楼主| 发表于 2026-8-6 21:51:17 | 显示全部楼层
FishC 发表于 2026-6-20 11:20
确实不是这样。让我用通俗的方式帮你理清浮点数的实际存储机制。

首先,float 类型在内存中占用固定的32 ...

C语言中 double类型强制转化int 是四舍五入还是小数裁剪
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-6 21:51:24 | 显示全部楼层
11063216906 发表于 2026-08-06 21:51
FishC 发表于 2026-6-20 11:20
确实不是这样。让我用 ...


在 C 语言中,将 double 强制转换成 int 时,既不是四舍五入,也不是简单的“向下取整”,而是 **直接截断小数部分**,也就是 **向零取整**(truncation towards zero)。

例如:
- (int)3.99  结果是 3
- (int)-3.99 结果是 -3

注意区别:
- 向零取整:3.99 变成 3,-3.99 变成 -3
- 向下取整(floor):3.99 变成 3,-3.99 变成 -4

所以它把小数部分直接扔掉,正数和负数都往零的方向靠拢。

如果你希望四舍五入,需要使用标准库中的 round() 函数,例如 int x = (int)round(3.6); 结果为 4。

如果小数超出 int 能表示的范围,结果是未定义行为,编译器可能给出错误值或异常,建议转换前先检查范围。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-6 22:05:29 | 显示全部楼层
@FishC
  1. case 'a':
  2.                         case 'A': a++;
  3.                                   break;
复制代码

这种写法a的情况下不会报错吗
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-6 22:05:33 | 显示全部楼层
11063216906 发表于 2026-08-06 22:05
@FishC case 'a':
                        case 'A' ...

这种写法完全不会报错,而且是 C 语言中非常常见的“多标签共用一段代码”的写法。


case 'a':case 'A': 紧挨着写时,如果表达式的值是 'a''A',都会执行后面的 a++;,直到遇到 break; 才会跳出 switch。

所以这段代码的意思是:无论输入小写 a 还是大写 A,变量 a 都会自增 1。

  1. switch (ch) {
  2.     case 'a':
  3.     case 'A':
  4.         a++;
  5.         break;
  6. }
复制代码


这种写法简洁高效,不用写两遍 a++;,放心使用。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-6 22:09:07 | 显示全部楼层
FishC 发表于 2026-8-6 22:05
当 case 'a': 和 case 'A': 紧挨着写时,如果表达式的值是 'a' 或 'A',都会执行后面的 a++;,直到 ...

我该如何用gcc去编译c语言代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-6 22:09:12 | 显示全部楼层
11063216906 发表于 2026-08-06 22:09
FishC 发表于 2026-8-6 22:05
当 case 'a': 和 case  ...


在命令行中,使用 gcc 编译 C 代码的基本格式是:

gcc 源文件名.c -o 输出文件名

例如,你有一个 hello.c 文件,想生成可执行程序 hello,就输入:

gcc hello.c -o hello

编译成功后会生成一个名为 hello 的可执行文件(Windows 下是 hello.exe),运行它:

./hello

如果不想指定输出文件名,直接输入 gcc hello.c,默认生成 a.out(Windows 下是 a.exe)。

如果你需要开启警告和调试信息,可以加上 -Wall -g,比如:

gcc -Wall -g hello.c -o hello

如果你的代码使用了数学库(比如 sqrt、pow),编译时需要链接数学库,加 -lm:

gcc hello.c -o hello -lm

如果有多个源文件一起编译,直接全部列出来:

gcc main.c helper.c -o program

这样就能轻松编译运行你的 C 代码了。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-6 22:17:12 | 显示全部楼层
FishC 发表于 2026-8-6 22:09
在命令行中,使用 gcc 编译 C 代码的基本格式是:

gcc 源文件名.c -o 输出文件名

expected identifier or '(' before numeric constant
这是什么报错
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-6 22:17:17 | 显示全部楼层
11063216906 发表于 2026-08-06 22:17
FishC 发表于 2026-8-6 22:09
在命令行中,使用 gcc  ...


这个报错通常表示你在不该出现数字的地方写了数字,常见原因是:你把数字当成了宏名、变量名或者函数名来使用。

例如:

  1. #define 5 100
  2. int main() { return 0; }
复制代码


或者:

  1. int 5a = 10;
复制代码


或者某个宏展开后变成了一个数字开头的东西,比如:

  1. #define NUM 10
  2. int NUM;
复制代码


不过上面这个其实是合法的(NUM 是宏名),真正常见的是:

  1. int 123abc;
复制代码


这行代码中,123abc 以数字开头,不是合法的标识符,编译器看到数字 123 后面跟着字母时,就会报出这个错误。

另一个典型场景是:你把宏定义写成这样:

  1. #define 3.14 PI  // 错误!宏名不能是数字开头
复制代码


修复方法很简单:检查出错的行(编译器通常会提示行号),把所有以数字开头的名字改成合法的标识符(字母或下划线开头),并且不要把数字字面量用作宏名。

如果你把代码贴出来,我可以帮你具体指出哪一行有问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-6 22:28:59 | 显示全部楼层
FishC 发表于 2026-8-6 22:17
这个报错通常表示你在不该出现数字的地方写了数字,常见原因是:你把数字当成了宏名、变量名或者函数名 ...

我在使用getchar这个函数的时候
  1. char ch = getchar();
  2. while(ch != '\n')
复制代码

程序会卡死不动
但我
  1. while((char ch = getchar()) != '\n')
复制代码

就没有问题 这是为什么
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-6 22:29:25 | 显示全部楼层
11063216906 发表于 2026-08-06 22:28
FishC 发表于 2026-8-6 22:17
这个报错通常表示你在 ...


你说得对,程序“卡死”其实就是**死循环**,而不是电脑卡住了。原因在于两种写法中 `getchar()` 被调用的次数完全不同。

先看第一种写法:

char ch = getchar();
while (ch != '\n')
{
    // 循环体
}

这里 `getchar()` 只在循环前执行一次。如果第一次读到的字符不是换行符,那么 `ch` 的值就永远是那个字符。只要循环体里没有再次修改 `ch`(也没有 `break` 跳出),条件 `ch != '\n'` 就一直成立,于是无限循环,看起来就像卡死。

再看你写的第二种:

while ((char ch = getchar()) != '\n')
{
    // 循环体
}

这里 `getchar()` 被放在了循环条件里,每次循环开始都会重新读取一个字符。所以它会不断读入下一个字符,直到读到换行符为止,不会死循环。

不过要注意:在标准 C 语言中,`while` 的条件里不能这样定义变量,`while ((char ch = getchar()) != '\n')` 实际上是语法错误(C++ 部分标准允许)。正确写法应该是:

int ch;
while ((ch = getchar()) != '\n')
{
    // 循环体
}

顺便提醒,`getchar()` 返回的是 `int`,用 `char` 保存可能会把 EOF 误判成普通字符,所以用 `int` 更安全。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-9 19:24:58 | 显示全部楼层
FishC 发表于 2026-8-6 22:29
你说得对,程序“卡死”其实就是**死循环**,而不是电脑卡住了。原因在于两种写法中 `getchar()` 被调 ...

为什么每次循环会往后读取一个字符
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-9 19:25:08 | 显示全部楼层
11063216906 发表于 2026-08-09 19:24
FishC 发表于 2026-8-6 22:29
你说得对,程序“卡死 ...


因为 getchar() 每次被调用时,都会从输入缓冲区中读取下一个字符,并把缓冲区的位置向后移动一格。所以把 getchar() 写在循环条件里,就等于每次循环开始前都执行一次“读取下一个字符”的操作。

具体流程:  
第一次进入循环条件,getchar() 读走第一个字符。  
如果它不是换行符,进入循环体执行。  
执行完循环体后,再次判断条件,getchar() 又读走第二个字符。  
如此反复,每次条件判断都会消费掉一个新的字符,直到读到换行符才停止。

而你最初那种写法:

char ch = getchar();
while (ch != '\n')
{
    // 没有修改 ch
}

getchar() 只在循环前执行了一次,ch 的值永远不变。循环条件永远成立,所以程序会一直循环下去,看起来就像卡死。

另外提醒:标准 C 中 while 条件里直接写 (char ch = getchar()) 是不合法的,建议这样写:

int ch;
while ((ch = getchar()) != '\n')
{
    // 处理字符
}

使用 int 类型还可以正确判断 EOF。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-9 19:27:10 | 显示全部楼层
FishC 发表于 2026-8-9 19:25
因为 getchar() 每次被调用时,都会从输入缓冲区中读取下一个字符,并把缓冲区的位置向后移动一格。所 ...

那我用ch = getchar()  存储字符
prinf 的时候是怎么依次向后读取的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-9 19:27:24 | 显示全部楼层
11063216906 发表于 2026-08-09 19:27
FishC 发表于 2026-8-9 19:25
因为 getchar() 每次被 ...


你的疑问在于:getchar 每次读一个字符,那 printf 是怎么做到“依次向后读取”的?其实它们属于两个方向的操作,不要混淆。

  • getchar() 负责从输入流(键盘/缓冲区)读取字符,每调用一次,内部会记住当前读取位置,下次调用自动读下一个字符。
  • printf() 负责向屏幕输出,如果使用 %s 输出字符串,它会从你提供的地址开始,依次读取内存中的字符,直到遇到 '\0' 才停止。


所以,如果你用 ch = getchar() 只能保存当前读到的那个字符。要想连续读多个字符,必须循环调用 getchar,并把它们存起来。

例如:


  1. char buf[100];
  2. int i = 0;
  3. int ch;

  4. while ((ch = getchar()) != '\n' && i < 99) {
  5.     buf[i++] = ch;
  6. }
  7. buf[i] = '\0';  // 手动添加字符串结束符

  8. printf("%s\n", buf);  // 从 buf 首地址开始依次输出
复制代码


这里 getchar 每次循环读取一个字符存入 buf,循环结束后 buf 中保存了一串字符,printf 用 %s 输出时,就会从 buf[0] 开始逐个输出,直到遇到 '\0'。

如果只是输出单个字符,直接用:


  1. char ch = getchar();
  2. printf("%c\n", ch);
复制代码


注意:getchar 返回的是 int 类型,建议用 int 保存,避免把 EOF 误判成普通字符。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-9 19:34:44 | 显示全部楼层
FishC 发表于 2026-8-9 19:27
你的疑问在于:getchar 每次读一个字符,那 printf 是怎么做到“依次向后读取”的?其实它们属于两个方 ...

那就是说getchar得到的一串字符例如ch = 'hello'
print('%c', ch);的时候是用指针去调用的 但如果我只是运行一次getchar那就是h
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-9 19:34:51 | 显示全部楼层
11063216906 发表于 2026-08-09 19:34
FishC 发表于 2026-8-9 19:27
你的疑问在于:getchar ...


你的理解需要纠正几个关键点:

  • getchar() 一次只读取一个字符,不是“得到一串字符”。如果你的输入是 hello,那么第一次调用 getchar() 返回的是 'h',第二次调用返回 'e',第三次返回 'l',依此类推。它不会一次性把所有字符都取出来。
  • 所以 不会出现 ch = 'hello' 这种赋值。'hello' 是字符串字面量,只能存放在字符数组或指向字符的指针中,例如 char str[] = "hello"; 或者 char *str = "hello"; 而普通的 char 变量只能存一个字符,如 'h'。
  • printf("%c", ch) 是按值传递单个字符,不是通过指针。你传入的是 ch 这个变量里存储的字符本身。只有 printf("%s", str) 才需要传入字符串首地址(也就是指针)。
  • 如果只运行一次 getchar(),它确实只读取输入缓冲区中的第一个字符。比如输入 hello 并回车后,缓冲区里是 h e l l o \n,第一次 getchar() 只取走 h,剩下的 e l l o \n 还在缓冲区里。


所以你的结论“如果只运行一次getchar那就是h”是正确的,但要注意 getchar 并不会自动“依次向后读取”,而是每次调用时才向后移动一个字符的位置。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-9 19:44:06 | 显示全部楼层
FishC 发表于 2026-8-9 19:34
你的理解需要纠正几个关键点:

1100 1100 –> -2^7 + 2^6 + 2^3 + 2^2 = -128 + 64 + 8 + 4 = -52
给我解释一下 我怎么知道2^7应该是负的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-9 19:44:11 | 显示全部楼层
11063216906 发表于 2026-08-09 19:44
FishC 发表于 2026-8-9 19:34
你的理解需要纠正几个 ...


关键就在于:这台计算机把 11001100 当成 **有符号二进制补码** 来解读。

补码的规则是:

- 最高位(最左边那位)的权重是 **负的 2^(位数-1)**
- 其余位的权重都是正的

对于 8 位二进制 11001100:

- 第7位(最高位)是 1,所以贡献 -2^7 = -128
- 第6位是 1,贡献 +2^6 = 64
- 第3位是 1,贡献 +2^3 = 8
- 第2位是 1,贡献 +2^2 = 4
- 其他位是 0,贡献 0

加起来:-128 + 64 + 8 + 4 = -52

所以你不需要“猜”2^7是负的,而是因为 **你明确知道这是补码表示的有符号数**。补码的最高位天然带着负号权重。如果把同样的 11001100 当作无符号数,那么它就是 204,不是 -52。

一句话记忆:有符号补码中,最高位是“负权位”,只要是1,就直接减 2^(n-1)。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-8-9 19:49:49 | 显示全部楼层
FishC 发表于 2026-8-9 19:44
关键就在于:这台计算机把 11001100 当成 **有符号二进制补码** 来解读。

补码的规则是:

1111 1101这个东西是十进制的多少 补码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-8-9 19:49:56 | 显示全部楼层
11063216906 发表于 2026-08-09 19:49
FishC 发表于 2026-8-9 19:44
关键就在于:这台计算 ...


1111 1101 按补码解释,十进制是 **-3**。

计算方法(权重法):
- 最高位是符号位,权重为 -2^7 = -128
- 其余位正常按正权重相加:64 + 32 + 16 + 8 + 4 + 0 + 1 = 125
- 总结果:-128 + 125 = -3

也可以这样记忆:补码取反加一
- 1111 1101 取反:0000 0010
- 再加 1:0000 0011(即 3)
- 所以原数是 -3

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-9-19 04:54

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表