C语言基础(运算符【详细篇】)

C语言基础

内容提要

  • 回顾
  • C语句
  • 数据的输入输出

回顾

运算符

算术运算符

结果:数值

+ - * / % +(正) -(负) ++ --

i++和++i

相同点:i自身都会增一

不同点:它们的运算的最终结果是不同的。i++:先使用,后计算;++i:先计算,后使用

举例:

// i++
int a = 1;
int b = a++;
printf("a=%d,b=%d\n",a,b);//a=2,b=1

// ++i
int x=1;
int y=++x;
printf("x=%d,y=%d",x,y);//x=2,y=2
赋值运算符

结果:赋值后的变量的值

= += -= *= /= %=

赋值顺序:由右到左

举例:

int i=0;
int sum=0;
sum += i;//等价于sum=sum+i
关系运算符

表达式=运算符+运算数

关系表达式=关系运算符+运算数

结果:布尔类型(默认结果:0代表假,非0代表真;引入stdbool.h文件,flase代表假,true代表真)

举例:

#include <stdbool.h>

bool is_flag = ture;//引入stdbool.h的真

int is_flag =ture;//默认的真

> < >= <= != ==

注意:

①两个浮点型数据进行比较的时候,不能使用==,因为比较出来色结果是不准确的,解决方法:参与比较的两个操作数相减,跟0比较,举例:

float a = 22.1,b = 22.1;
a - b == 0;//a=b
a - b > 0;//a>b
a - b < 0;//a<b
逻辑运算符

结果:布尔类型

&& || !

&&:运算符左右两侧表达式都成立,则结果为真;有一个不成立,则结果为假。

||:运算符左右两侧表达式都不成立,则结果为假;有一个不成立,则结果为真。

!:对原操作数或者表达式结果取反,如果原操作数或者表达式结果为真,则最终结果为假;反之最终结果为真。

在这里插入图片描述

偶数:!(a%2==0)取反之后变奇数

奇数:!(a%!=0)取反之后变偶数

惰性运算

惰性运算的目的是减少运算次数,从而提供运算效率。

短路与:如果&&左侧表达式返回假,就不再执行右侧的表达式,最终返回的结果就是左侧表达式的结果(假)

短路或:如果||左侧表达式返回真,就不再执行右侧表达式,最终返回的结果就是左侧表达式的结果(真)

逗号运算符(面试题)

结果:最后一个表达式的结果

语法:表达式1,表达式2,...,表达式n

位运算

所谓的位运算,就是计算机底层直接针对二进制位进行操作

& | ~ ^ << >>

~:按位取反,单目运算符,针对二进制位,每一位进行取反,结果二进制位0变1,1变0。

&:按位与,双目运算符,两个数相同二进制位,如果都为1,结果为1,否则结果为0

|:按位或,双目运算符,两个数相同的二进制位,有一个为1,结果为1,否则结果为0

^:按位异或,双目运算符,两个数相同的二进制位,如果相同,结果为0;否则为1

<<:左移,分为无符号左移和有符号左移,所有二进制位从地位到高位依次左移,超出部分舍弃,缺失部分使用0补齐。举例:5<<6,快捷公式:5*2^6,但是有符号数高位都是1的时候,快捷公式就不适用了。

>>:右移,分为无符号右移和有符号右移,所有二进制从高位到低位依次右移,超出部分舍弃,缺失部分分情况。

​ ①无符号右移:直接补0

​ ②有符号右移:算术右移(默认补1),逻辑右移(补0),这个由计算机系统决定

扩展:

char a; // -128~127 占1字节

unsigned char b; // 0~255 占1字节

char 有符号:

1 1111111 ~ 1 0000000 负数+0 -0 -128~0

0 1111111 ~ 0 0000000 正数+0 +0 127~0

char 无符号:

00000000 ~ 11111111 正数+0 0 ~ 255

流程控制

程序 = 算法 + 数据结构

算法:操作的步骤

数据结构:数据的描述

流程控制三大基本结构

① 顺序结构:默认

② 分支结构:(条件结构、选择结构)根据条件选择性执行,又被分为:单分支(单路分支)、双分支(双路分支)、多分支(多路分支)

③ 循环结构:(重复结构)根据条件重复执行,又被分为:当型循环(先判断,后执行)、直到型循环(先执行,后判断)

流程控制

C语句

定义
  • C程序是以函数为基础单位的。
  • 一个函数的执行部分是由若干条语句构成的。
  • C语句都是用来完成一定的操作任务。
  • C语句必须依赖于函数存在。
C程序结构

在这里插入图片描述

C语句分类
控制语句

用于完成一定的控制功能

①if…else…

②for…

③while…

④do…while

⑤continue

⑥break

⑦switch

⑧return

⑨goto

函数调用语句

由一个函数调用加一个分号组成,例如:

printf("这是一个c程序!\n");
test();
表达式语句

由一个表达式加一个分号构成,最典型的表达式语句就是赋值语句,例如:

a=3   //是一个表达式
score >= 90  //是一个表达式
score = 90//是一个表达式语句
空语句

只有一个分号,什么都不做,例如:

;//(面试题)可以执行
复合语句

用"{…}"括起来的若干个语句,例如:

{
    z=x+y;
    t=z/100;
    printf("%f\n",t);
}

一般形式为:{语句部分;}

数据的输入输出

数据的输入与输出是相对而言的,其中:

  • 从计算机向外部设备输送数据称之为输出。通常的输出设备包括:显示器、打印机等。

  • 从外部设备向计算机输送数据称之为输入。通常的输入设备包括:键盘、鼠标、扫描仪等。

    在C语言中,输入与输出需要使用标准的输入输出库(stdio.h)中的输入函数(scanf())、输出函数(printf())实现。

    库函数已经被编译成了目标文件,在链接时与编译源程序得到的目标文件(.obj)相链接,生成可执行程序。

    注意:在使用系统库函数时,要用预处理指令#include将有关的头文件包含到用户源文件中(要放在程序的开头位置)头文件中包含了调用函数时需要的有关信息,具体的函数在编译的时候再去链接对应的系统库。

    简单的输入与输出
    用简单的printf函数输出数据

    语法:

    printf("格式控制",输出列表)

    注意:格式控制中的格式化符号(如%d)要和输出的数据一一对应。

    举例:

    printf("i=%d,x=%d,y=%d\n",i,34,i+1);
    

    ①格式控制:

    1.格式说明:由%特定字符组成,如:%d,%f。%u等,这是格式说明符,用于说明输出项目所采用的格式。

    2.普通字符:作为说明性文符号等,照原样显示出来。

    ②输出列表:输出列表:输出;列表中的各项目指出了索要输出的内容,可以是常量、变量、表达式。

    基本的格式字符

    %d 按有符号十进制整型(int)数据的实际长度输出。(十进制(0)、八进制(00)、十六进

    制(0x00))

    %u 按无符号十进制整型(int)数据的实际长度输出。

    %c 仅输出一个字符(char)

    %s 输出结果是字符串,举例:printf(“%s\n”,“CHINA”);,输出结果:CHINA

    %f 以小数形式输出一个实数(涵单双精度)。整数部分全部输出,小数部分输出6位。

    %e 也可以写作%E,以指数形式输出一个实数(涵单双精度)。小数点前1位非0数字,并输出6位小数。

    %hd 短整型(short int/short)

    %hhd 字符型的ASCII码,char数据对应的ASCII码的值,举例:char a = ‘A’;printf(“%hhd\n”,a);,输出结果:65

    %lf 双精度浮点型(double)

    %ld 长整型(long int/long)

    %lld 长长整型(long long int/long long)

    printf(“i=%d,x=%d,y=%d\n”,i,34,i+1);

    %x 十六进制,但是十六进制的前缀0x不会打印出来,举例:printf(“%x,%#x\n”,198,198);,输出结果:c6,0xc6

    %#x 十六进制,并且十六进制的前缀0x也会打印出来,举例:0x05

    %#o 八进制,并且八进制的前缀0也会打印出来,举例:05

    %p 打印内存的地址

用简单的scanf函数输入数据

语法:

scanf("格式控制",地址列表);//首地址

注意:不能传变量、常量、表达式,只能传与之对应的内存地址(首地址)

举例:

int a = 10;//定义了一个变量a
scanf("%d",&a);//&被称作取地址符,&a意思获取a变量对应的内存地址(首地址)
printf("%p\n",a);//打印输出a的内存地址(首地址)

作用:将从键盘输入的值存入内存中所占的存储单元里。存储单元有地址标识。

说明:

  • 格式控制:含义等同于printf函数的格式控制,说明输入的数据应该使用的格式,但是格式控制中不能添加除格式化符以外的字符
  • 地址列表:是由若干个地址组成的,可以时变量的地址或者字符串的首地址。&是取地址运算符,用于取出变量的地址。与格式化输出一样,在格式控制中,用于说明数据格式的格式说明符以%开头,后面紧跟具体的格式。

案例:

  • 需求:从键盘输入整数给变量a,b,c

  • 代码:

    #include <stdio.h>
    
    int main()
    {
        int a,b,c;
        printf("请输入三个整数:\n");
        scanf("%d %d %d",&a,&b,&c);
        printf("a=%d,b=%d,c=%c\n",a,b,c);
        
        return 0;
    }
    

    注意:输入的数据可用空格、Tab键、回车键中的任意一种方式。

    在这里插入图片描述

  • 说明:

    • scanf函数中的"格式控制"后面应当是变量的地址,由取地址运算符&和变量名共同组成,不能仅是变量名:scanf(“%f%d”,&a,&b);

    • 如果"格式控制"中除了格式说明还有其他字符,则在输入数据时必须在对应位置输入与之相同的字符:

      scanf(“%d,%d”,&a,&b);

      从键盘录入的时候必须输入逗号:3,4

      scanf(“%d年%d月%d日”,&year,&month,&day);

      从键盘录入的时候必须输入逗号:2025年2月10日

    • 用%c格式输入字符时,空格和转义字符(\n)都作为有效字符输入,应注意:scanf(“%c%c%c”,&a,&b,&c);

      只有输入:xyz

      才能得到a=x,b=y,c=z

    • 再输入数值型数据(整形+浮点型)时,遇到空格、回车、Tab键或遇到非法输入,则认为该数据结束:

    • 对于unsigned型变量所需的数据,可以用%u或%d格式输入。

复杂的输入输出

按指定格式输出数据的宽度、小数位数、上下行数据按小数点对齐、用八位、十六位输出等

输出数据格式的控制
整形格式说明符
  • 十进制形式(0~9)

    说明符说明数据类型
    %d和%md用于基本整形int
    %ld和%mld用于长整型long
    %u和%mu用于无符号基本整形unsigned int
    %lu和%mlu用于无符号长整型unsigned long
  • 八进制形式(0~7)

    说明符说明数据类型
    %o和%mo用于基本整形int
    %lo和%mlo用于长整型long
  • 十六进制(0~f)

    说明符说明数据类型
    %x和%mx用于基本类型int
    %lx和%mlx用于长整型long

    m表示输出整形数据所占总宽度(即列数),其中:

    ①当实际数据的位数不到m位时,数据前面将用空格填满;

    ②若实际数据的位数大于m位时,则以数据的实际位数为准进行输出;

    一个int型整数也可以用%u输出,反之一个unsigned型整数也可以用%d、%o、%x格式输出。按相互赋值的规则处理。

    举例:

    #include <stdio.h>
    int main(int argc,char *argv[])
    {
        printf("%d\n",12); // 实际只占2列,12
        printf("%6d\n",12); // m是正数,实际占了6列,前面不足的使用空格填充♦♦♦♦12
        printf("%-6d\n",12); // m是负数,实际占了6列,后面不足的使用空格填充12♦♦♦♦
        printf("%6d\n",12345678); // 如果实际的数据列宽超过了规定的列宽,列宽效,按照实际显示,12345678
        
        return 0;
    }
    
字符型格式说明符
  • 字符型

    说明符说明举例
    %c或者%mc输出的字符占m列printf(“%c\n”,‘a’);
  • 字符串型

  • 在C语言中,是支持字符串常量的,但是不支持字符串变量。

    说明符说明举例
    %ms输出的字符串占m列。若串长>=m,全部输出;反之在串前补空格(m为补空格)printf(“%6s\n”,hello); // ♦hello
    %-m输出的字符串占m列。若串长>=m,全部输出;反之在串前补空格(m为补空格)printf(“%-6s\n”,hello); // hello♦
    %m.ns输出的字符串占m列。只取字符串前n个字符,不足部分串前补空格。printf(“%6.2s\n”,“hello”); // ♦♦♦♦he
    %-m.ns输出的字符串占m列。只取字符串前n个字符,不足部分串后补空格。printf(“%-6.2s\n”,“hello”); // he♦♦♦♦

    注意:一个整数,只要其值在0255范围内,也可以用%c格式按其字符形式输出。这里0127对应ASCII码。

    在输出前,系统会自动将整数作为ASCII码转换成相应的字符;反之,一个字符也可以输出成一个整数。

    案例:

    • 要求:字符串输出

    • 代码:

      #include <stdio.h>
      
      int main()
      {
          printf("%s,%7.2s,%-5.3s,%.4s","CHINA","CHINA","CHINA","CHINA");
      }
      
    • 运行结果:

      CHINA,♦♦♦♦♦CH,CHI♦♦,CHIN

浮点型格式说明符

浮点型格式分为三种形式:

  • 十进制形式:%m.nf或者%-m.nf

  • 指数形式:%m.ne或者%-m.ne

  • %g或者%G形式:根据数值的大小,自动选择%f或者%e中宽度较短的一种形式,不输出无意义的0。

    解释:

    在输出浮点型数据时,格式说明符中的m表示整个数据所占的列宽,n表示小数点后面所占的位数

    (保留的小数位)

    如果在小数点后取n位后,所规定的数据宽度m不够输出数据前面的整数部分(包括小数点),则

    按实际的位数进行输出。

    在C语言中,用于输出单精度浮点型与双精度浮点型数据格式说明符是一样的

    案例1:

    • 要求:输出浮点型数时,指定小数位。

    • 代码:

      #include <stdio.h>
      
      int main()
      {
          float f = 123.456;
          printf("%8.2f,%-8.2f,%8.6f,%8.2e,%g\n",f,f,f,f,f);
          
          return 0;
      }
      
    • 运行结果:

      ♦♦123.46,123.46♦♦,123.456001,1.23e+02,123.456 123.456==1.23456*10^2 ==1.23456e^2

    案例2:

    • 要求:求3个圆的周长,输出结果时上下按小数点对齐,取两位小数。

    • 代码:

      #include <stdio.h>
      #define PI 3.1415926
      void main ( )
      {
          double r1=1.53,r2=21.83,r3=123.71,s1,s2,s3;
          s1=2.0*PI*r1;
          s2=2.0*PI*r2;
          s3=2.0*PI*r3;
          printf("%6.2f\n",s1);//保留两位小数,结果不超过六位,前面补空格
          printf("%.2f\n",s2);//保留两位小数
          printf("%.2f\n",s3);//保留两位小数
      }
      
    • 运行结果:
      在这里插入图片描述

    案例:

    • 要求:设有如下C程序

    • 代码:

      #include "stdio.h"
      
      int main()
      {
          double x=34.567;
          printf("x=%f\n",x);// 34.567000
          printf("x=%d\n",x);// 27263,这种写法错误,自动类型转换异常
          printf("x=%d\n",(int)x);//34
          
          return 0;
      }
      
    • 这个程序的实际运行结果为

      x=34.567000

      x=27263

      x=34

    • 说明

      显然,这个程序中的第二个格式输出语句输出的结果是错误的,这是因为在第二个格式输出语句中,格式说明符%d是基本整型格式说明符,而输出项目是双精度型的数据,它们是不匹配的。

输入数据格式的控制
整形格式说明符
  • 十进制形式

    说明符说明数据类型
    %d用于基本整形int
    %ld用于长整型long
    %u用于无符号基本整形unsigned
    %lu用于无符号长整型unsigned long
  • 八进制形式

    说明符说明数据类型
    %o用于基本类型int
    %lo用于长整型long
  • 十六进制形式

    说明符说明数据类型
    %x用于基本类型int
    %xl用于长整型long

    可见:

    ①用于输入与输出整形数据的格式说明符是完全一致的。

    ②与输出情形一样,对于八进制与十六进制的输出格式,主要用于输入无符号的整形数据。

浮点型格式说明符
  • 单精度浮点型:%f或者%e

  • 双精度浮点型:%lf

    可见:

    ① 与输出不同,输入时无论是单精度还是双精度浮点型,都不能用m.n来指定输出的宽度和小

    数点后的位数。

    ② 可以指定输入数据所占的列数,系统自动按他截取所需数据,如:

    scanf("%3d%3d",&a,&b); 当输入1234567时,a得到123,b得到456,多余的7无用。

    ③ 若在%后有一个 * 和一个数字,表示跳过他指定的列数,如:scanf("%2d%*3d%3d",&a,&b); 当输入12345678时,a得到12,%*3d表示跳过3列,b得到的是678

    案例:

    #include <stdio.h>
    int main()
    {
        int a,b;
        scanf("%3d%3d",&a,&b);// 输入1234567,a=123,b=456
        
        return 0;
    }
    
    • 当用于输入整型数据的格式说明符中没有宽度说明时,则在具体输入数据时分为以下两种情况:

      ① 如果各格式说明符之间没有其它字符,则在输入数据时,两个数据 之间用"空格"、或"Tab"、或"回车"来分隔。

      ② 如果各格式说明符之间包含其它字符,则在输入数据时,应输入与 这些字符相同的字符作为间隔。

      例如,设有如下说明

      int a,b;

      float c,d;

      现要利用格式输入函数输入a=12,b=78,c=12.5,d=7.6。 采用不同的格式说明,其输入数

      据的形式也是不同的。分别说明如下:

      • 若输入语句为 scanf(“%d%d%f%f”,&a,&b,&c,&d); (即格式说明符中没有宽度说明,各格式说明符之间也没有其他字符。)

        则输入数据的形式应为 12 78 12.5 7.6 (两个数据之间用空格来分隔,当然也可用“Tab”或“回车”来分隔。)

      • 若输入语句为 scanf(“%d,%d,%f,%f”,&a,&b,&c,&d);(格式说明符中没有宽度说明,但各格式说明符之间有其它字符,即逗号)

        则输入数据的形式应为 12,78,12.5,7.6 (即在输入的两个数据之间同时要输入逗号。)

      • 若输入语句 scanf(“a=%d,b=%d,c=%f,d=%f”,&a,&b,&c,&d); (即格式说明符中没有宽度说明,但各格式说明符之间有其它字符。)

        输入数据的形式应为 a=12,b=78,c=12.5,d=7.6 (即在输入的两个数据之间同时要输入这些非格式说明符的字符。)

      • 在用于输入的实型格式说明符中不能用m.n来指定输入的宽度和小数点后的位数(这是与输出的不同之处)。

        例如: scanf("%7.2f",&a); × 此用法是错误的

      • 为了便于程序执行过程中从键盘输入数据,在一个C程序开始执行时,系统就在计算机内存中开辟了一个输入缓冲区,用于暂存从键盘输入的数据。开始时该输入缓冲区是空的。当执行到一个输入函数时,就检查输入缓冲区中是否有数据;

扩展:输入输出缓冲机制

缓冲区的概念

  • 缓冲区(也称为缓存)是内存空间的一部分,用于暂存输入或输出的数据。

  • 在进行输入操作时,系统从外部设备(如键盘)读取数据,先放入缓冲区,程序再从缓冲区中读取数据。

  • 在进行输出操作时,系统先将数据放入缓冲区,然后在特定条件下(如缓冲区满、遇到特定字符、手动刷新等)再将缓冲区中的数据输出到外部设备(如屏幕)。

缓冲区的类型

C语言的缓冲区有三种类型:

  • 全缓冲:当缓冲区填满后,才进行实际的输入输出操作。例如,对磁盘文件的读写。 —window 全缓冲大小4096字节 linux 全缓冲大小1024字节

  • 行缓冲:当在输入和输出中遇到换行符时,执行实际的输入输出操作。例如,标准输入(stdin)和标准输出(stdout)。

  • 无缓冲:不进行缓冲,直接进行输入输出操作。例如,标准错误流(stderr)。

缓冲区的刷新条件

缓冲区的刷新(即将缓冲区中的数据实际输出到外部设备)通常发生在以下情况之一:

  • 缓冲区满:当缓冲区写满时,会自动刷新。

  • 遇到特定字符:如换行符(\n)。

  • 手动刷新:使用fflush(stdout)函数手动刷新输出缓冲区。

  • 程序关闭时:当程序结束时,缓冲区中的数据会被刷新。

缓冲区的实际应用

  • 提高效率:通过缓冲区,可以减少与外部设备的交互次数,提高数据传输的效率。

  • 处理输入输出:例如,使用scanf和printf函数时,数据先被放入缓冲区,然后按照特定的规则从缓冲区中读取或输出。

原理实现

在这里插入图片描述

注意事项

  • 在处理输入时,特别是连续输入多个数据时,需要注意缓冲区中可能残留的数据,这可能会影响后续的输入操作。

  • 在使用fflush(stdin)来清空输入缓冲区时,需要注意这是未定义行为,在标准C中并不推荐这种做法。

扩展:进制转换

进制转换

我们目前接触到的进制有 二进制、八进制、十进制、十六进制

  • 其他进制 转 十进制:

    按权相加

    1.(1234)10 = 4 * 10^0 + 3 * 10^1+2 * 10^2 + 1 * 10^3

    2.(0x1234)16 = 4 * 16^0 + 3 * 16^1 + 2 * 16^2 +1 * 16^3

  • 十进制转其他进制:

    辗转相除法:将需要转换的数据不停的除以转换的进制数,直到商为0

    ① 十进制转二进制:
    在这里插入图片描述

    ② 十进制转八进制:

    在这里插入图片描述

  • 八进制转十六进制:

    借助于二进制,将八进制转换为二进制,将二进制转换为十六进制。

  • 十六进制转八进制:

    借助于二进制,将十六进制转换为二进制,将二进制转换为八进制。

    0xA9F = 1010 1001 1111 (二进制) = 101 010 011 111 (二进制) = 0 5 2 3 7

​ 分(二进制) 合(八进制)

​ 0xE139A = 0B1110 0001 0011 1001 1010 = 011 100 001 001 110 011 010 = 03411632

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值