C语言入门复习

本文是C语言的基础复习,涵盖了基本语法、变量、运算符、流程控制和数据类型等内容。讲解了printf函数的使用、变量的声明与赋值、各种运算符的运用,包括算术、关系、逻辑、位运算符,以及流程控制结构如if、switch、循环等。此外,还介绍了数据类型中的字符、整数和浮点数,以及它们的进制、格式化输出和范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、基本语法

printf()

基本用法

printf() 的作⽤是将参数⽂本输出到屏幕。f 代表 format (格式化)

printf() 是在标准库的头⽂件 stdio.h 定义的。使⽤这个函数之前,必须在源码⽂件头部引⼊这个头文件。

#include <stdio.h>
int main(void) {
 printf("Hello World\n");
}

2、变量

变量名

变量名属于标识符(identifier)

  • 只能由字⺟(包括⼤写和⼩写)、数字和下划线( _ )组成。
  • 不能以数字开头。
  • ⻓度不能超过63个字符。
  • 区分大小写,star,Star,STAR都是不同的变量

变量的声明

每个变量都有⾃⼰的类型(type)

int height, width;
// 等同于
int height;
int width;

变量的赋值

C 语⾔会在变量声明时,就为它分配内存空间,但不会清除内存⾥⾯原来的值。变量会是⼀个随机的值。所以 变量⼀定要赋值以后才能使⽤。

变量的声明和赋值,通常写在一行。

  • 赋值表达式有返回值,等于等号右边的值。

    int x, y, z, m, n;
    x = y = z = m = n = 3;
    

    ⼀次为多个变量赋值。赋值运算符是从右到左执⾏,所以先为 n 赋值,然后依次 为 m 、 z 、 y 和 x 赋值。

C 语⾔有左值(left value)和右值(right value)的概念。左值是可以放在赋值运算符左边的值,⼀般是变量;右值是可以放在赋值运算符右边的值,⼀般是⼀个具体的值。这是为了强调有些值不能放在赋值运算符的左边,⽐如 x = 1是合法的表达式,但是 1 = x 就会报错。

变量的作用域

作用域(scope)指的是变量⽣效的范围。C 语⾔的变量作⽤域主要有两种:⽂件作⽤域(file scope)和 块作⽤域(block scope)。

**文件作用域(file scope)**是指:在源码⽂件顶层声明的变量,从声明的位置到⽂件结束都有效。

  int x = 1;
  int main(void) 
{
  printf("%i\n", x);
}

x在文件顶层声明,从声明位置开始的整个当前⽂件都是它的作⽤域。

**块作用域(block scope)**是指:由⼤括号{ } 组成的代码块,它形成⼀个单独的作⽤域。凡是在块作用域里面声明的变量,只在当前代码块有效。

int a = 12;

if(a == 12){
    int b ==99;
    printf("%d %d\n",a,b);  //输出12 99
}
    printf("%d\n",a);    //输出12
    printf("%d\n",b);    //出错

代码块可以嵌套

{
    int i = 10;
        if(i == 10){
            int i = 20;
            printf("%d\n",i);  //输出20
        }
    printf("%d\n",i);    //输出10
}

注意:因为是“声明”,所以才会这样,正常只是“赋值”


specially :for 的循环条件部分是⼀个单独的作⽤域

  //循环条件
for(int i = 0;i < 5;i++)  
  //循环体内部
{
    int i = 999;
    printf("%d\n", i);  //输出5次999
}

由于循环条件部分是⼀个单独的作⽤域,所以循环体内部的 i 不会修改掉循环变量 i ,因此这段代码的运⾏结果就是打印5次 999 。


3、运算符

算数运算符

  • + :正值运算符(⼀元运算符)
  • - :负值运算符(⼀元运算符)
  • + :加法运算符(⼆元运算符)
  • - :减法运算符(⼆元运算符)
  • * :乘法运算符
  • / :除法运算符
  • % :余值运算符
(1)+ - 没什么要说的

⼀元运算符 + 对正负值没有影响,是⼀个完全可以省略的运算符,但是写了也不会报错。

int x = -12;
int y = +x;   //y还是-12 
(2)* 就乘法
(3)/

Pay attention: 两个整数相除,得到还是⼀个整数。

float x = 6 / 4;
printf("%f\n", x);   // 输出 1.000000

C语言里面的整数除法是整除,只会返回整数部分,丢弃小数部分

两个运算数必须⾄少有⼀个浮点数

float x = 6.0 / 4;   // 或者写成 6 / 4.0printf("%f\n", x);   // 输出 1.500000

another example:

int score = 5;
score = (score / 20) * 100;    //只会输出0

5/20=0.25,但都是整数,返回整数部分0


(4) %

表示求模运算,即返回两个整数相除的余值。这个运算符只能⽤于整数,不能用于浮点数。

负数求模的规则是,结果的正负号由第⼀个运算数的正负号决定。

11 % -5  // 1
-11 % -5 // -1
-11 % 5  // -1
(5)赋值运算的简写形式
i += 3; // 等同于 i = i + 3
i -= 8; // 等同于 i = i - 8
i *= 9; // 等同于 i = i * 9
i /= 2; // 等同于 i = i / 2
i %= 5; // 等同于 i = i % 5

自增运算符,自减运算符

  • ++
  • - -

太简单 不写了


关系运算符

C 语⾔⽤于⽐较的表达式,称为“关系表达式”(relational expression),⾥⾯使⽤的运算符就称为“关系运 算符”(relational operator)

  • > ⼤于运算符
  • < ⼩于运算符
  • >= ⼤于等于运算符
  • <= ⼩于等于运算符
  • == 相等运算符
  • != 不相等运算符

specially:

i < j < k

不会报错,但达不到想要的目的。

i < j 返回值是0或1,最终0或1与 k 进行比较。

应该用:i < j && j < k


逻辑运算符

  • ! :否运算符(改变单个表达式的真伪)。

  • && :与运算符(两侧的表达式都为真,则为真,否则为伪)。

  • || :或运算符(两侧⾄少有⼀个表达式为真,则为真,否则为伪)。

trait: 逻辑运算符总是先对左侧的表达式求值,再对右边的表达式求值

if (number != 0 && 12/number == 2)

如果 && 左侧的表达式( number != 0 )为伪,即 number 等于 0 时,右侧的表达式 ( 12/number == 2 )是不会执⾏的。因为这时左侧表达式返回 0 ,整个 && 表达式肯定为伪,就直接返回 0 ,不再执行右侧的表达式了。

位运算符

C 语⾔提供⼀些位运算符,⽤来操作⼆进制位(bit)。

(1)取反运算符 ~

取反运算符 ~ 是⼀个⼀元运算符,用来将每⼀个⼆进制位变成相反值,即 0 变成 1 , 1 变成 0 。

// 返回 01101100
~ 10010011

Pay attention: ~ 运算符不会改变变量的值,只是返回⼀个新的值。

(2)与运算符 &

与运算符 & 将两个值的每⼀个⼆进制位进⾏⽐较,返回⼀个新的值。当两个⼆进制位都为 1 时,返回 1 , 否则返回 0 。

// 返回 00010001
10010011 & 00111101

与运算符 & 可以与赋值运算符 = 结合,简写成 &=

i = i & 2;i &= 2;
(3)或运算符 |

或运算符 | 将两个值的每⼀个⼆进制位进⾏⽐较,返回⼀个新的值。两个⼆进制位只要有⼀个为 1 (包含 两个都为 1 的情况),就返回 1 ,否则返回 0 。

// 返回 1011111110010011 | 00111101

或运算符 | 可以与赋值运算符 = 结合,简写成 |=

(4)异或运算符 ^

异或运算符 ^ 将两个值的每⼀个⼆进制位进⾏⽐较,返回⼀个新的值。两个⼆进制位有且仅有⼀个为 1时 , 就返回 1 ,否则返回 0 。

// 返回 10101110 10010011 ^ 00111101

异或运算符^ 可以和赋值运算符 = 结合,简写为^=

(5)左移运算符 <<

左移运算符<<讲左侧运算数的每一位,向左移动指定的位数,尾部空出来的位置使⽤ 0 填充。

// 1000101000
10001010 << 2

左移运算符 << 可以与赋值运算符 = 结合,简写成 <<=

(6)右移运算符 >>

右移运算符 >> 将左侧运算数的每⼀位,向右移动指定的位数,尾部⽆法容纳的值将丢弃,头部空出来的位 置使⽤ 0 填充。

// 返回 00100010
10001010 >> 2

Pay attention: 右移运算符最好只⽤于⽆符号整数,不要⽤于负数。


右移运算符 >> 可以与赋值运算符 = 结合,简写成 >>=

逗号运算符

逗号运算符返回最后⼀个表达式的值,作为整个语句的值。

int x;x = 1, 2, 3;

逗号的优先级低于赋值运算符,所以先执行赋值运算,再执行逗号运算,变量 x 等于 1 。

运算优先级

部分运算符的优先级顺序(按照优先级从⾼到低排列)

  • 圆括号( () )
  • ⾃增运算符( ++ ),⾃减运算符( – )
  • ⼀元运算符( + 和 - )
  • 乘法( * ),除法( / )
  • 加法( + ),减法( - )
  • 关系运算符( < 、 > 等)
  • 赋值运算符( = )

完全记住所有运算符的优先级没有必要,解决⽅法是多⽤圆括号,防⽌出现意料之外的情况,也有利于提⾼ 代码的可读性。


4、流程控制

条件执⾏和循环执⾏

if语句

dddd

三元运算符 ?:

if…else的简写形式

?:

表达式expression1为ture(非0值)时,就执行expression2,否则就执行expression3

examole:

(i > j)? i : j

返回两个值之中的较大值,等同于:

if (i > j)
 return i;
else
 return j;

switch语句

dddd

while 语句

do…while 结构

for 语句

break语句

两种用法:1.与switch语句配套使用,用来中断某个分支的执行。

2.在循环体内部跳出循环,不再进行后面的循环。

while ((ch = getchar()) != EOF) {
 if (ch == '\n') break;
 putchar(ch);
}

读取到换行符(\n),break命令就跳出整个while循环,不在读取了

Pay attention: break命令只能跳出switch结构,不能跳出if结构。

continue 语句

用于在循环体内部终止本轮循环,进入下一论循环。

while ((ch = getchar()) != EOF) {
 if (ch == '\t') continue;
 putchar(ch);
}

读取到换行符(\t),就用continue语句跳过该字符,读取下一字符。

goto 语句

goto 语句⽤于跳到指定的标签名

char ch;
top: ch = getchar();
if (ch == 'q')
 goto top;

top就是一个标签名,可以放在正常语句前面,相当于做了一个标记。

goto的一个主要用法就是跳出多层循环

for(...) {
   for (...) {
     while (...) {
       do {
         if (some_error_condition)
           goto bail; 
       } while(...);
     } 
   }
}
 
bail:
// ... ...

不用goto的话,想跳出所有循环,很麻烦。

goto的另一个用途是 提早结束多重判断

if (do_something() == ERR)
 goto error;
if (do_something2() == ERR)
 goto error;
if (do_something3() == ERR)
 goto error;
if (do_something4() == ERR)
 goto error;

上面四个判断,发现一个错误,就能用goto跳过后面的判断。

Pay attentiion: goto只能在同一个函数之中跳转,并不能跳转到其他函数。

5、数据结构

基本的数据类型有三个:字符(char)、整数(int)、浮点数(float)。

字符类型

C 语言规定,字符常量必须放在单引号里面。

在计算机内部,字符类型使用一个字节(8位)存储。c语言将其当作整数处理。

只要在字符类型的范围之内,整数与字符是可以互换的。(0 到 127 的 ASCII 字符范围)。

char c = 66;
//等同于
char c = 'B';

单引号本身也是一个字符,如果要表示这个字符常量,要使用反斜杠转义。

char t = '\'';
  • \a :警报,这会使得终端发出警报声或出现闪烁,或者两者同时发⽣。
  • \b :退格键,光标回退⼀个字符,但不删除字符。
  • \f :换页符,光标移到下⼀⻚。在现代系统上,这已经反映不出来了,行为改成类似于 \v 。
  • \n :换行符。
  • \r :回车符,光标移到同⼀⾏的开头。
  • \t :制表符,光标移到下⼀个⽔平制表位,通常是下⼀个8的倍数。
  • \v :垂直分隔符,光标移到下⼀个垂直制表位,通常是下⼀⾏的同⼀列。
  • \0 :null 字符,代表没有内容。注意,这个值不等于数字0。

转义写法还有使用八进制和十六进制表示一个字符。

  • \nn : 字符的⼋进制写法, nn 为⼋进制值。
  • \xnn :字符的⼗六进制写法, nn 为⼗六进制值。
char x = 'B';
char x = 66;
char x = '\102'; // ⼋进制
char x = '\x42'; // ⼗六进制

整数类型

int

表示较大的数,常见是使用4个字节(32位)存储一个int类型。

  • 16位:-32,768 到 32,767。
  • 32位:-2,147,483,648 到 2,147,483,647。
  • 64位:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。
signed,unsigned

int 等同于 signed int

16位:

  • signed int 范围:-32,768 到 32,767
  • unsigned int 范围: 0 到 65,535

字符类型 char 也可以设置 signed 和 unsigned 。

signed char c;   // 范围为 -128 到 127
unsigned char c; // 范围为 0 到 255
整数的子类型

int 太大了,对于小整数浪费空间。对于太大的,还会不够用。

  • short int (简写为short):占用空间不多于int,一般占用两个字节(整数范围为-32768~32767)。
  • long int (简写为long) : 占用空间不少于int,至少为4个字节。
  • long long int (简写为 long long ):占⽤空间多于 long ,⾄少为8个字节。

C 语⾔允许省略 int

整数类型的极限值

有时候需要查看,当前系统不同整数类型的最⼤值和最⼩值,C 语⾔的头⽂件 limits.h 提供了相应的常量

  • SCHAR_MIN , SCHAR_MAX :signed char 的最⼩值和最⼤值。
  • SHRT_MIN , SHRT_MAX :short 的最⼩值和最⼤值。
  • INT_MIN , INT_MAX :int 的最⼩值和最⼤值。
  • LONG_MIN , LONG_MAX :long 的最⼩值和最⼤值。
  • LLONG_MIN , LLONG_MAX :long long 的最⼩值和最⼤值。
  • UCHAR_MAX :unsigned char 的最⼤值。
  • USHRT_MAX :unsigned short 的最⼤值。
  • UINT_MAX :unsigned int 的最⼤值。
  • ULONG_MAX :unsigned long 的最⼤值。
  • ULLONG_MAX :unsigned long long 的最⼤值。
整数的进制

c语言的整数默认都是十进制

八进制用0做前缀

int a = 012; //八进制,相当于十进制的10

十六进制用0x0X做前缀

int a = 0x1A2B; //十六进制,进制相当于十进制的6699

有些编译器使⽤ 0b 前缀,表示⼆进制数,但不是标准。

int x = 0b101010;

printf() 的进制相关占位符如下。

  • %d :⼗进制整数。
  • %o :⼋进制整数。
  • %x :⼗六进制整数。
  • %#o :显示前缀 0 的⼋进制整数。
  • %#x :显示前缀 0x 的⼗六进制整数。
  • %#X :显示前缀 0X 的⼗六进制整数。
输出格式
(1)限定宽度
printf("%5d\n",123);   //右对齐,输出"  123"
printf("%-5d\n",123);  //左对齐,输出"123  "

对于小数,这个限定符会限制所有数字的最小显示宽度

// 输出 " 123.450000"
printf("%12f\n", 123.45);

%12f表示输出的浮点数最少要占据12位,因为小数的默认显示精度是小数点后6位,所以在123.45的头部添加了两个空格。

(2)总是显示正负号
printf("%+d\n", 12); // 输出 +12
printf("%+d\n", -12); // 输出 -12

不改变正负。

(3)限定小数位数

希望给小数点后只保留两位,占位符可以写成 %.2f

// 输出 Number is 0.50
printf("Number is %.2f\n", 0.5);

同时限定宽度

// 输出 Number is "  0.50"
printf("Number is %4.2f\n",0.5);

//等同于
printf("Number is %*.*f\n",4,2,0.5);
(4)输出部分字符串

%s占位符用来表示输出的字符串,默认全部输出。如果主要开头的部分,可以用%.[m]s指定输出的长度

// 输出 hello
printf("%.5s\n","hello world");

浮点数类型

浮点数的类型声明使⽤ float 关键字,可以⽤来声明浮点数变量。

m * be 的形式,存储⼀个数值, m 是小数部分, b 是基数(通常是 2 ), e 是指数部分

float 类型占⽤4个字节(32位),其中8位存放指数的值和符号,剩下24位存放⼩数的值和符号。 float 类型⾄少能够提供(⼗进制的)6位有效数字,指数部分的范围为(⼗进制的) -37 到 37 ,即数值范围为 10-37到1037

两个更大的浮点数类型:

  • double:占用8个字节(64位),至少提供13位有效数字。
  • long doube: 通常占用16个字节。

Pay attention:由于存在精度限制,浮点数只是一个近似值,计算是不精确的

if (0.1 + 0.2 == 0.3) // false

可以用科学计数法

double x = 123.465e+3; //123.456 x 10^3
//等同于
double x = 123.456e3;

布尔类型

使用0表示伪,所有非零值表示真。

C99标准里添加的类型_Bool表示布尔值

_Bool number;
number = 1;
if(number)
{  printf("is ture.\n");  }

头文件stdbool定义了另一个类型别名bool并且定义了 true 代表 1 、 false 代表 0 。只要加载这 个头⽂件,就可以使⽤这⼏个关键字。

#include <stdbool.h>
bool flag = false;

字面量的值

字面量(literal)指代码里直接出现的值

int = 123;

123就是字面量。编译时,字面量也会写入内存,所以编译器必须为字面量指定数据类型(就像必须为变量指定数据类型⼀ 样)。

一般情况下十进制的整数123会被编译器认定为int型,如果超过了int的范围,就认定为long int,再超就unsigned long

字面量后缀(有什么用?)

f 和 F : float 类型。

l 和 L :对于整数是 long int 类型,对于⼩数是 long double 类型。

ll 和 LL :Long Long 类型,⽐如 3LL 。

u 和 U :表示 unsigned int ,⽐如 15U 、 0377U 。

溢出

每一个数据类型都有数值范围,超出之后,需要更多的二进制位存储,向上溢出(overflow),向下溢出(underflow)

unsigned char x = 255;
x += x;
printf("%d\n",x);   //输出0

运算时如果为了避免溢出,有个方法就是将运算结果与类型的极限值进行比较。

unsigned int a,b,sum;
//正确
if(a > UINI_MAX - B) too_big();
else sum = a + b;if(a > UINI_MAX - B) too_big();
else sum = a + b;

//错误 因为a + b 的结果本身就是溢出值,小于UINI_MAX
if(a + B> UINI_MAX) too_big();
else sum = a + b;

siezof运算符

返回某个数据类型或某个值占用的字节数量。它的参数可以是数据 类型的关键字,也可以是变量名或某个具体的值。

sizeof 运算符的返回值,C 语⾔只规定是⽆符号整数,并没有规定具体的类型,⽽是留给系统⾃⼰去决 定, sizeof 到底返回什么类型。不同的系统中,返回值的类型有可能是 unsigned int ,也有可能 是 unsigned long ,甚⾄是 unsigned long long ,对应的 printf() 占位符分别是 %u 、 %lu 和 %llu 。 这样不利于程序的可移植性。

C 语⾔提供了⼀个解决⽅法,创造了⼀个类型别名 size_t ,⽤来统⼀表示 sizeof 的返回值类型。该别名 定义在 stddef.h 头⽂件(引⼊ stdio.h 时会⾃动引⼊)⾥⾯,对应当前系统的 sizeof 的返回值类型,可 能是 unsigned int ,也可能是 unsigned long 。

C 语⾔还提供了⼀个常量 SIZE_MAX ,表示 size_t 可以表示的最⼤整数。所以, size_t 能够表示的整数 范围为 [0, SIZE_MAX] 。

printf() 有专⻔的占位符 %zd 或 %zu ,⽤来处理 size_t 类型的值。

类型的自动转换

赋值运算

(1)浮点数值赋予整数变量

c语言直接舍弃小数部分

int x = 3.14;  //x = 3

直接舍弃,不是四舍五入。

(2)整数赋值给浮点数变量

自动转换为浮点数

float x = 4;    //x = 4.0

(3)窄类型赋值给宽类型

字节较小的整数类型,赋值给字节宽度较大的整数类型时,就是窄变宽

char x = 10;
int i = x + 10;

变量 x 的类型是 char ,由于赋值给 int 类型,所以会⾃动提升为 int 。

(4)宽类型赋值给窄类型

会发生类型降级,自动转换为后者。这时可能会 发⽣截值(truncation),系统会⾃动截去多余的⼆进制位,导致难以预料的结果。

int i =321;
char ch = i;    //ch的值位65  (321-255)

浮点数赋值给整数类型的值,也会发⽣截值,浮点数的⼩数部分会被截去。

double pi = 3.14159;
int i = pi; // i 的值为 3
混合类型的运算

小的转大的,窄的转宽的

最好避免无符号整数与有符号整数的混合运算。因为这时 C 语⾔会⾃动将 signed int 转 为 unsigned int ,可能不会得到预期的结果。

整数类型的运算*

两个相同类型的整数运算时,或者单个整数运算时,一般来说运算结果也是同一类型。

但有一个例外,宽度小于int类型,运算结果会自动提升为int的类型

unsigned char a = 66;

if((-a) < 0)
    printf("negative\n");
else
    printf("positive\n");

变量a时unsigned char类型,不能小于0,但(-a)会自动转换为int类型,导致上面的代码输入negative。

函数

函数的参数和返回值,会自动转换为函数定义里指定的值

int example(int a, unsigned char b)

    char m = 42;
    unsigned short n = 43;
    long long int c = example(m,n)
       //m n的类型,传入后 会变成example里定义的参数类型
char example(void)
{
    int a = 42;
    return a;    //返回的还是char 因为函数定义的char
}

类型的显式转换

手动转换类型的方法

在一个值或者变量前面,使用圆括号指定类型(type),就可以使这个之或者变量转为指定的值。叫做“类型指定(casting)”。

(unsigned char) ch

ch 转成⽆符号的字符类型

long int y = (long int) x + 10

(long int) 将 x 显式转为 long int 类型

可移植类型**

在声明时,准确控制变量的字节宽度,头⽂件 stdint.h 创造了⼀些新 的类型别名。

(1)精确宽度类型(exact-width integer type),保证某个整数类型的宽度是确定的。

int8_t :8位有符号整数。

int16_t :16位有符号整数。

int32_t :32位有符号整数。

int64_t :64位有符号整数。

uint8_t :8位⽆符号整数。

uint16_t :16位⽆符号整数。

uint32_t :32位⽆符号整数。

uint64_t :64位⽆符号整数。

(2)最小宽度类型(minimum width type),保证某个整数类型的最小长度。
int_least8_t
int_least16_t
int_least32_t
int_least64_t
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t

可以保证占据的字节不少于指定宽度

(3)最快的最⼩宽度类型(fast minimum width type),可以使整数计算达到最快的类型。
int_fast8_t
int_fast16_t
int_fast32_t
int_fast64_t
uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
上⾯这些类型是保证字节宽度的同时,追求最快的运算速度

⽐如 int_fast8_t 表示对于8位有符号整数, 运算速度最快的类型。这是因为某些机器对于特定宽度的数据,运算速度最快

(4)可以保存指针的整数类型。

intptr_t :可以存储指针(内存地址)的有符号整数类型。
uintptr_t :可以存储指针的⽆符号整数类型。

(5)最⼤宽度整数类型,⽤于存放最⼤的整数。

intmax_t :可以存储任何有效的有符号整数的类型。
uintmax_t :可以存放任何有效的⽆符号整数的类型。
上⾯的这两个类型的宽度⽐ long long 和 unsigned long 更⼤。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值