c语言—变量—操作符—输入输出

变量

C语⾔中把经常变化的值称为变量,不变的值称为常量。

变量命名的⼀般规则:

• 只能由字⺟(包括⼤写和⼩写)、数字和下划线(`_`)组成。

• 不能以数字开头。 • ⻓度不能超过63个字符。

• 变量名中区分⼤⼩写的。

• 变量名不能使⽤关键字。

变量的分类

• 全局变量:在⼤括号外部定义的变量就是全局变量 全局变量的使⽤范围更⼴,整个⼯程中想使⽤,都是有办法使⽤的。

• 局部变量:在⼤括号内部定义的变量就是局部变量 局部变量的使⽤范围是⽐较局限,只能在⾃⼰所在的局部范围内使⽤的。

变量的存储

内存中的三个区域:栈区、堆区、静态区

1. 栈区(Stack)

  • 用途:存储局部变量、函数参数、函数返回地址等。

  • 管理方式:由编译器自动分配和释放,遵循后进先出(LIFO)原则。

  • 特点

    • 高效:分配和释放仅通过移动栈指针完成,速度快。

    • 有限大小:栈空间通常较小(默认几MB,取决于系统),溢出会导致Stack Overflow错误。

    • 生命周期:变量的生命周期与函数调用周期一致,函数结束时自动释放。

    • void func() {
          int x = 10; // x存储在栈区
          char buffer[1024]; // 数组也在栈区
      } // 函数结束,x和buffer自动释放

      2. 堆区(Heap)

    • 用途:动态分配的内存(如mallocnew等)。

    • 管理方式:由程序员手动分配和释放(或由垃圾回收机制管理,如Java/Python)。

    • 特点

      • 灵活:空间远大于栈(受限于系统可用内存),可动态调整大小。

      • 手动管理:需显式释放(C/C++中free/delete),否则会导致内存泄漏。

      • 碎片化:频繁分配/释放可能产生内存碎片。

int *p = (int*)malloc(100 * sizeof(int)); // 在堆区分配100个int
free(p); // 必须手动释放

3. 静态区(Static/Global Storage)

  • 用途:存储全局变量static变量、常量(如字符串常量)。

  • 管理方式:在程序编译时分配,生命周期持续到程序结束。

  • 细分区域

    • .data段:已初始化的全局变量和静态变量。

    • .bss段:未初始化的全局变量和静态变量(程序启动时自动清零)。

    • .rodata段:只读数据(如字符串常量)。

  • 特点

    • 持久性:变量在整个程序运行期间存在。

    • 线程安全:全局变量需注意多线程同步问题。

int global_var = 1;         // 已初始化全局变量(.data段)
static int static_var;       // 未初始化静态变量(.bss段)
const char* str = "Hello";  // 字符串常量(.rodata段)

对比总结

特性栈区堆区静态区
管理方式编译器自动管理程序员手动管理编译器/系统管理
生命周期函数调用结束即释放直到显式释放或程序结束整个程序运行期间
大小限制较小(MB级)大(GB级,受系统限制)编译时确定
访问速度极快(CPU缓存友好)较慢(需指针间接访问)快(地址固定)
典型数据局部变量、函数参数动态分配的对象、数组全局变量、静态变量

注意

  1. 栈溢出:递归过深或局部变量过大(如大数组)会触发栈溢出。

  2. 内存泄漏:堆区分配后未释放会导致内存耗尽。

  3. 线程安全:静态区的全局变量在多线程中需加锁保护。

运算符

类别操作符名称作用示例
算术操作符+加法计算两个数的和a + b
-减法计算两个数的差a - b
*乘法计算两个数的积a * b
/除法计算两个数的商(整数除法会截断小数部分)a / b
%取模(求余)计算两个数相除的余数(仅适用于整数)a % b
关系操作符==等于判断两个值是否相等a == b
!=不等于判断两个值是否不相等a != b
>大于判断左边的值是否大于右边的值a > b
<小于判断左边的值是否小于右边的值a < b
>=大于等于判断左边的值是否大于或等于右边的值a >= b
<=小于等于判断左边的值是否小于或等于右边的值a <= b
逻辑操作符&&逻辑与如果两个操作数都为真(非零),则结果为真a && b
||逻辑或如果任意一个操作数为真(非零),则结果为真a||b
!逻辑非对操作数取反(真变假,假变真)!a
位操作符&按位与对两个数的二进制位进行与运算a & b
|按位或对两个数的二进制位进行或运算a|b
^按位异或对两个数的二进制位进行异或运算(相同为0,不同为1)a ^ b
~按位取反对一个数的二进制位取反(0变1,1变0)~a
<<左移将二进制位向左移动指定位数,低位补0a << 2
>>右移将二进制位向右移动指定位数(逻辑右移补0,算术右移补符号位)a >> 2
赋值操作符=赋值将右边的值赋给左边的变量a = 10
+=加后赋值a += b 等价于 a = a + ba += 5
-=减后赋值a -= b 等价于 a = a - ba -= 3
*=乘后赋值a *= b 等价于 a = a * ba *= 2
/=除后赋值a /= b 等价于 a = a / ba /= 4
%=取模后赋值a %= b 等价于 a = a % ba %= 3
&=按位与后赋值a &= b 等价于 a = a & ba &= 0xF
|=按位或后赋值a|= b等价于a = a|ba|=0x1
^=按位异或后赋值a ^= b 等价于 a = a ^ ba ^= 0xFF
<<=左移后赋值a <<= b 等价于 a = a << ba <<= 1
>>=右移后赋值a >>= b 等价于 a = a >> ba >>= 2
递增/递减++递增变量值加1(a++ 后缀,++a 前缀)a++ 或 ++a
--递减变量值减1(a-- 后缀,--a 前缀)a-- 或 --a
条件操作符?:三元条件运算符条件 ? 表达式1 : 表达式2,如果条件为真返回表达式1,否则返回表达式2a > b ? a : b
逗号操作符,逗号运算符从左到右计算多个表达式,返回最后一个表达式的值a = (b=3, b+2) → a=5
指针操作符*解引用获取指针指向的值int *p; *p = 10;
&取地址获取变量的内存地址int a; int *p = &a;
结构体/联合体.成员访问(对象)访问结构体或联合体的成员struct.x
->成员访问(指针)通过指针访问结构体或联合体的成员p->x
sizeofsizeof计算大小返回变量或类型的大小(字节数)sizeof(int)
类型转换(type)强制类型转换将变量或值转换为指定类型(float) a
下标操作符[]数组下标访问数组元素arr[3]

 关系表达式通常返回 0 或 1 ,表⽰真假。C语⾔中, 0 表⽰假,所有⾮零值表⽰真。

 正号(+)和负号(-)运算符

  1. +作为单目运算符时对数值没有影响,可以省略

  2. -作为单目运算符时会反转操作数的符号:

    • 正数变负数

    • 负数变正数

 强制类型转换

用途

  1. 将较大类型转换为较小类型(可能丢失数据)

  2. 将浮点数转换为整数(截断小数部分)

  3. 在不同指针类型之间转换

  4. 避免编译器警告

 占位符列举

C语言输入/输出占位符总表

1. 标准输出占位符(printf 家族)
占位符类型修饰符示例说明示例代码
%dint%5d有符号十进制整数(左补空格)printf("%5d", 42); → ∙∙42
%iint%+i同 %d,可识别八/十六进制输入printf("%i", 012); → 10
%uunsigned int%08u无符号十进制(补零)printf("%08u", 42); → 00000042
%ounsigned int%#o无符号八进制(# 加前缀 0printf("%#o", 8); → 010
%xunsigned int%#x无符号十六进制小写(0x 前缀)printf("%#x", 255); → 0xff
%Xunsigned int%04X无符号十六进制大写printf("%04X", 255); → 00FF
%ffloat/double%.2f十进制浮点数(保留2位小数)printf("%.2f", 3.1415); → 3.14
%efloat/double%.3e科学计数法小写(eprintf("%e", 1000.0); → 1.000000e+03
%Efloat/double%10.2E科学计数法大写(Eprintf("%E", 0.001); → 1.00E-03
%gfloat/double%g自动选择 %f 或 %e(更简洁):6个有效数字的浮点数。整数部分⼀旦超过6位,就会⾃动转为科学计数法,指数部分的 e 为⼩写printf("%g", 0.0001); → 0.0001
%Gfloat/double%G自动选择 %f 或 %E。等同于 %g ,唯⼀的区别是指数部分的 E 为⼤写。printf("%G", 1.0e5); → 1E+05
%cchar%c单个字符printf("%c", 'A'); → A
%schar*(字符串)%10s字符串(右对齐)printf("%10s", "Hi"); → ∙∙∙∙∙∙∙∙Hi
%pvoid*(指针)%p指针地址(十六进制)printf("%p", &num); → 0x7ffd...
%nint*%n记录已输出的字符数int cnt; printf("Hi%n", &cnt); → cnt=2
%%%%输出 % 符号printf("%%"); → %
%a⼗六进制浮点数,字⺟输出为⼩写
%A⼗六进制浮点数,字⺟输出为⼤写

 最⼩宽度和⼩数位数这两个限定值,都可以⽤ * 代替,通过 printf() 的参数传⼊, %*.*f 的两个星号通过 printf() 的两个参数 6 和 2 传⼊

 #include <stdio.h>
 int main()
 {
 printf("%*.*f\n", 6, 2, 0.5);
 return 0;
 }
 // 
等同于printf("%6.2f\n", 0.5); 

 如果只想输出开头的部分,可以⽤ 的⻓度,其中 [m] 代表⼀个数字,表⽰所要输出的⻓度。

 // 
输出
 hello 
#include <stdio.h>
 int main()
 {
 printf("%.5s\n", "hello world");
 return 0;
 }

2. 标准输入占位符(scanf 家族)
占位符类型修饰符示例说明示例代码
%dint*%d有符号十进制整数scanf("%d", &num);
%iint*%i可识别八进制(0)、十六进制(0x)输入scanf("%i", &num);(输入 012 → 10
%uunsigned int*%u无符号十进制整数scanf("%u", &unum);
%ounsigned int*%o无符号八进制scanf("%o", &unum);
%xunsigned int*%x无符号十六进制scanf("%x", &unum);
%ffloat*%f十进制浮点数(floatscanf("%f", &fval);
%lfdouble*%lf十进制浮点数(doublescanf("%lf", &dval);
%Lflong double 类型浮点数
%e/%Efloat*/double*%e科学计数法输入(同 %f/%lfscanf("%e", &fval);
%cchar*%c单个字符(包括空格/换行)scanf("%c", &ch);
%schar[](字符串)%10s字符串(遇空格停止,需指定长度防溢出)scanf("%9s", str);(缓冲区大小为10)
%pvoid**%p指针地址scanf("%p", &ptr);
%[]char[]%[a-z]自定义字符集(如只读小写字母)scanf("%[A-Z]", str);
%nint*%n记录已读取的字符数scanf("H

 scanf() 处理数值占位符时,会⾃动过滤空⽩字符,包括空格、制表符、换⾏符等。所以,⽤⼾输⼊的数据之间,有⼀个或多个空格不影响 scanf() 解读数据。另外,⽤⼾使⽤回⻋ 键,将输⼊分成⼏⾏,也不影响解读

scanf() 的返回值是⼀个整数,表⽰成功读取的变量个数,如果没有读取任何项,或者匹配失败,则返回 0 。 如果在成功读取任何数据之前,发⽣了读取错误或者遇到读取到⽂件结尾,则返回常量EOF(-1)。

注意:

  • %c 不忽略空⽩字符,总是返 回当前第⼀个字符,⽆论该字符是否为空格。
  • 如果要强制跳过字符前的空⽩字符,可以写成 scanf(" %c", &ch) ,即 ⽰跳过零个或多个空⽩字符。
  • 特别说⼀下占位符 %s ,它其实不能简单地等同于字符串。它的规则是,从当前第⼀个⾮空⽩ 字符开始读起,直到遇到空⽩字符(即空格、换⾏符、制表符等)为⽌。 因为 %s 不会包含空⽩字符,所以⽆法⽤来读取多个单词,除⾮多个 %s ⼀起使⽤。另外, scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符 \0 。
  • scanf() 将字符串读⼊字符数组时,不会检测字符串是否超过了数组⻓度。所以,储存字符串时, 很可能会超过数组的边界,导致预想不到的结果。为了防⽌这种情况,使⽤ 读⼊字符串的最⻓⻓度,即写成 %[m]s ,其中的 %s 占位符时,应该指定 [m] 是⼀个整数,表⽰读取字符串的最⼤⻓度,后 ⾯的字符将被丢弃。 
 #include <stdio.h>
 int main()
 {
 char name[11];
scanf("%10s", name);
 return 0;
 }

 更安全的写法:

scanf("%19s", arr); // 限制最多读取19个字符

下面这种写法允许读取空格

  • 更安全的做法是指定最大读取长度:%19[^\n](留1字节给空终止符)即:

    scanf("%19[^\n]", arr); // 读取最多19个字符,直到遇到换行符
3. 长度修饰符(通用)
修饰符适用类型示例说明
hshort%hdshort int短整数
llong%ldlong int长整数
lllong long%lld长长整数(C99)
Llong double%Lf长双精度浮点数
zsize_t%zu无符号大小类型(C99)
tptrdiff_t%td指针差值类型(C99)

 赋值忽略符

 scanf() 提供了⼀个赋值忽略符(assignmentsuppressioncharacter) * 。 只要把 * 加在任何占位符的百分号后⾯,该占位符就不会返回值,解析后将被丢弃。

赋值忽略符是一个星号(*),放在%和格式说明符之间,例如:%*d

当使用这个修饰符时:

  1. scanf()会按照指定的格式读取输入

  2. 但不会将读取的值赋给任何变量

  3. 相当于"读取并丢弃"这部分输入

跳过不需要的数据

int year, month, day;
// 输入格式为 "YYYY-MM-DD"
scanf("%d%*c%d%*c%d", &year, &month, &day);
这里%*c会读取但跳过中间的连字符-。

跳过特定字段
int id;
char name[50];
// 输入为 "123:John Doe:42" 但我们不需要年龄
scanf("%d:%[^:]:%*d", &id, name);
这里%*d会读取但跳过最后的年龄值42。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值