C语言教程
C语言结构
#include<stdio.h> /*引入头文件*/
int main(void) /*一个简单的C程序*/
{
int number; /*定义个名字叫做number的变量*/
number=2014; /*给number赋一个值*/
printf("Hello ! I am dotcpp.com\n"); /*像屏幕打印一句话*/
printf("This year is %d\n",number);
return 0;
}
预处理语句+主函数
预处理语句
预处理语句主要有三类构成,分别是宏定义(
#define
),文件包含(
#include
)和条件编译(
#if
)。
宏定义(
#define
)
#define
宏定义相当于定义了一个全局变量,用全局变量来代替变量或者表达式。宏定义包含有参宏和无参宏。
宏定义
#define M (y*y+3*y);//无参宏,作用是指定标识符 M 来代替表达式(y*y+3*y)。
#define M(y) (y*y+3*y);//有参宏
宏调用
#define M(y) (y*y+3*y);//有参宏
int main(){
M(4);//输出的是4*4+3*4
}
文件包含(include)
(1)另外文件包含后面可以接
<>
或者
“”
,里面来包含要引入的文件(以下两种方式都是可以的),文件包含的作用是引入指定文件的所有内容。
#include "stdio.h"
#include <stdio.h>
尖括号表示在包含文件目录中去查找,而双引号则表示首先在当前的源文件目录中查找, 若未找到才到包含目录中去查找。
(2)一个 include 命令只能指定一个被包含文件,若有多个文件要包含,则需用多个 include 命令。
(3)文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。
条件编译(
#if
)
#if
条件编译存在3种形式
第一种形式:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
如果标识符被预定义过,则执行程序段1,否则执行程序段2。如果程序段2为空,则else可以不写。
#ifdef 标识符
程序段
#endif
第三种形式:
#ifndef 标识符
程序段 1 #else
程序段 2 #endif
如果标识符没有被预定义过,则执行程序段1,否则执行程序段2。
第三种形式:
#if 常量表达式
程序段 1 #else
程序段 2 #endif
如果常量表达式为真,则执行程序段1,否则执行程序段2。
其它预处理指令
1.
#error
:强制停止编译。
2.
# error-message
:遇到#error 指令时,显示错误信息和作者预先定义的其它内容。
3.
# line
:改变
__LINE__
和
__FILE__
的内容,
__LINE__
和
__FILE__
都是编译程序中预定义的标识符。
4.
# pragma
:允许由此向编译程序传入各种指令。
C语言的数据类型
基本数据类型
C语言的基本数据类型为:整型、字符型、浮点型。分别是:
short
、
int
、
long
、
char
、
float
、
double
等的有符号和无符号类型,有符号一般包含正负数,而无符号一般指的是正数。
下面列出了在32位操作系统下 常见编译器下的数据类型大小及表示的数据范围:
关键字
为了实现相应的功能,c语言中提供了一些关键字,在定义变量的时候注意不要和这些关键字重名,以下是c语言中的32个关键字。
C语言中的基本输入和输出
字符输出函数
putchar
putchar
putchar
函数是字符输出函数,其功能是在终端(显示器)输出单个字符。
int putchar(int ch);
ch表示要输出的字符内容,返回值作用为:如果输出成功返回一个字符的
ASC
码,失败则返回
EOF
即-1。
putchar(‘A’); /*输出大写字母A */putchar(x); /*输出字符变量x的值*/putchar(‘\n’); /*换行*/
字符输入函数
getchar
getchar
getchar
函数的功能是接收用户从键盘上输入的一个字符。
char c; /*定义字符变量c*/c=getchar(); /*将读取的字符赋值给字符变量c*/
格式化输出函数
printf
printf
printf
函数叫做格式输出函数,其功能是按照用户指定的格式输出内容。
printf
函数的格式为:
printf(“格式控制字符串”,输出表项);
格式控制字符串有两种:格式字符串和非格式字符串。非格式字符串在输出的时候原样打印;格式字符串是以%打头的字符串,在”%”后面跟不同格式字符,用来说明输出数据的类型、形式、长度、小数位数等。
格式字符串的形式为: % [输出最小宽度] [.精度] [长度] 类型
以下是格式字符串的类型
printf
中的修饰符
*
,它的作用是由程序来控制宽度。
/*使用可变宽度输出字段*/#include<stdio.h>int main(void){ unsigned width,precision; int number = 256; double weight = 25.5; printf("Please input number's width:\n"); scanf("%d",&width); printf("The number is: %*d\n",width,number); printf("Then please input width and precision:\n"); scanf("%d %d",&width,&precision); printf("Weight = %*.*f\n",width,precision,weight); return 0;}
格式化输入函数
scanf
scanf
scanf
函数称为格式输入函数,即将输入的内容格式化。
scanf
函数的调用的一般形式为:
scanf(“格式控制字符串”,输入项地址列表);
输入项地址列表由地址运算符
&
后跟变量名组成。
scanf
函数中格式字符串的构成与
printf
函数基本相同,但使用时有几点不同.
(1) 格式说明符中,可以指定数据的宽度,但不能指定数据的精度。例:
float a;scanf(“%10f”,&a); //正确scanf(“%10.2f”,&a); //错误
(2) 输入
long
类型数据时必须使用
%ld
,输入
double
数据必须使用
%lf
或
%le
。
scanf()
函数所用的转换说明符与
printf()
所用的几乎完全相同。主要区别在于
printf()
把
%f、%e、%E、%g、%G
同时用于
float
类型和
double
类型,而
scanf()
只是把他们用于
float
类型,而用于
double
类型时要求使用l(字母l)修饰符。
修饰符*在
scanf中()
的用法是使函数跳过相应的输入项目。
/*用*跳过scanf接收的数字*/#include<stdio.h>int main(void){ int num; printf("Please enter three number:\n"); scanf("%*d %*d %d",&num); printf("The last number is %d\n",num); return 0;}
scanf()
的返回值,
scanf()
函数返回成功读入的字符的个数,如果没有读取字符,则返回
0
。
运算符和表达式
基本运算符
赋值运算符
数学匀速符
#include<stdio.h>int main(){ int a=20; int b=5; int c=6; printf("a = %d b = %d c = %d\n",a,b,c); printf("a + b = %d\n",a+b); printf("a - c = %d\n",a-c); printf("a * b = %d\n",a*b); printf("a / c = %d\n",a/c); printf("a %% c = %d\n",a%c);/*两个%才会输出一个%*/ return 0;}
sizeof
运算符
sizeof
sizeof()
运算符的作用是返回一个数据类型和变量的字节大小。
#include<stdio.h>int main(){ int n=0; int intsize = sizeof(int); printf("int sizeof is %d bytes\n",intsize); return 0;}
三目运算符
三目运算符的一般形式如下:
表达式1?表达式2:表达式3
如果表达式
1
为真,则执行表达式
2
,否则执行表达式
3
。
表达式和语句
每个表达式以分号结尾,表示一个语句。
C语句和程序流
选择结构
选择结构有单选择、双选择和多选择3种形式。
单选择
if(表达式) /*若条件成立则实行花括号里的语句,反之则不执行*/ { //语句 }
双选择
if(表达式) /*若表达式成立则执行语句1,否则执行语句2*/ { //语句1 } else { //语句2 }
多选择
if(表达式) /*若表达式成立则执行语句1,否则执行语句2*/ { //语句1 } else { //语句2 }
多分支选择结构除了
else if
之外,C语言还提供了
switch
的结构。
switch
的执行过程是首先计算表达式的值,按照表达式的值执行相应的语句。
switch(表达式) /*首先计算表达式的值*/ { case 常量表达式1:语句1; case 常量表达式2:语句2; case 常量表达式3:语句3; // … … case 常量表达式n:语句n; default:语句n+1; }
switch(value){ case 1:printf("one");break; case 2:printf("two");break; case 3:printf("three");break; default:printf("other");break;}
循环结构
C语言提供三种循环结构,分别为
while
循环,
do while
循环和
for
循环
while
循环,满足表达式则进入循环。
while(表达式) { 循环体语句 }
while(i++<10){ printf(“count %d ”,i);}
do while
循环,先循环一次,然后判断是否满足表达式,满足表达式则继续循环。
do { 循环体语句 }while(表达式);
do{ printf("count %d",i);}while(i<20);
for循环,确定循环次数的循环。
for(初始化表达式;判断表达式;更新表达式) { 循环体语句 }
for(i=0;i<100;i++){ printf("i count is %d\n",i);}
函数
函数的定义
c语言中最简单的函数是
main()
主函数。
函数的定义通常包含以下内容: 返回值类型 函数名(形参表说明) /*函数首部*/ { 说明语句 /*函数体*/ 执行语句 }
1.函数的返回类型不能是数组,而是基本数据类型。
2.函数名不能和C语言中的关键字同名。
根据函数定义的一般形式,可以定义一个最简单的函数:
int main(){ return 0;}
函数的调用
变量的存储类型
C语言中的变量可以分为两种类型,及全局变量和局部变量。
C 语言中定义了 4 种类型的变量,即自动变量、外部变量、静态变量和寄存器变量,它们存储的位置有些不同。
自动变量
自动变量指的是在方法中定义的,用
auto
关键字修饰的变量。
int fun(int a){ auto int b,c=3; /*定义 b,c 为自动变量*/}
外部变量
外部变量指的是在方法外面定义的全局变量。
静态变量
静态变量指的在方法中定义的,用
static
关键字修饰的变量,静态变量在方法执行结束后不会消失。
寄存器变量
寄存器变量指的是在方法中定义的变量,用
register
关键字修饰的变量,
register
指的是存储在
CPU
寄存器中。
注意以下几点:
(1)只有局部自动变量和形式参数可以作为寄存器变量。
(2)一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量。
(3)不能使用取地址运算符“&”求寄存器变量的地址。
数组
一维数组的定义和使用
类型说明符 数组名 [常量表达式];
int a[100]; //定义一个数组名为a,存储100个int类型的数组,其元素分别是a[0]~a[99]float b[10]; //数组名为b的,存储10个float类型的数组,其元素分别是b[0]~b[9]char c[256]; //定义一个数组名为c的字符型数组 长度为256,其元素分别是c[0]~c[255]
int a[100]={1,2,3,4,5}; //定义一个整型数组a,前5个元素即赋值为1,2,3,4,5,后95个元素值值全部为0float b[10]={1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.0}; //定义float数组b并对全部float类型的元素都分别赋值char c[256]={'C','l','a','n','g','u','a','g','e'}; //定义一个数组名为c的字符型数组 并对前9个元素进行赋值,其余元素全部为'\0'
二维数组的定义和使用
二维数组的定义:
类型说明符 数组名[行数][列数];
int a[3][4];/*定义一个整形二维数组a,有3行4列共12个元素分别为:a[0][0] a[0][1] a[0][2] a[0][3]a[1][0] a[1][1] a[1][2] a[1][3]a[2][0] a[2][1] a[2][2] a[2][3]*/char arry[10][10];//定义一个字符型二维数组arry,有10行10列,依次为arry[0][0]~arry[9][9]供100个元素
int a[3][4]={{1,2,3,4},{10,20,30,40},{100,200,300,400}};//定义一个三行四列的二维数组,按行赋值int a[3][4]={1,2,3,4,10,20,30,40,100,200,300,400};//定义一个三行四列的二维数组并对其中的12(3*4)个元素进行赋值
字符数组和字符串
字符数组的定义和使用
char c[10];char c[6]={'c', ' h ', 'i', 'n', 'a' , '\0' };
对字符数组的各个元素逐个赋值后,各元素的值为:
c[0]= 'c',c[1]= 'h',c[2]= 'i',c[3]= 'n',c[4]= 'a',c[5]= '\0';
字符数组也可采用字符串常量的赋值方式,例如:
char a[]={"china"};
指针
地址与指针
在我们最广泛使用的32位操作系统下,变量的内存地址就是是从
0~4,294,967,295
之间的一个编号。在C语言中可以通过地址运算符
&
来得到变量的地址。
#include<stdio.h>int main(){ int i; int a[10]={1,2,3,4,5,6,7,8,9,0}; char b[10]={'c','l','a','n','g','u','a','g','e'}; for(i=0;i<10;i++) { printf("int Address:0x%x,Value:%d\n",&a[i],a[i]); } printf("\n"); for(i=0;i<10;i++) { printf("char Address:0x%x,Value :%c\n",&b[i],b[i]); } return 0;}
指针的定义和使用
指针和地址一样,代表的是在逻辑内存中的一个编号,但是地址是一个常量,而指针所对应的地址值是一个变量。
对指针变量定义的一般形式为:
类型说明符 *变量名;
#include<stdio.h>int main(){ int num=2014; int *p=# printf("num Address = 0x%x,num=%d\n",&num,num); printf("p = 0x%x,*p=%d\n",p,*p); printf("%d\n",*&num); return 0;}
注意:在32位操作系统下,任何类型的指针变量都占四个字节!
#include<stdio.h>struct INFO{ int a; char b; double c;};int main(){ int *p; char *p1; float *p2; double *p3; struct INFO *p4; //struct INFO类型为结构体类型 我们将会在后面的章节中讲解 void *p5; printf("int point size is :%d\n",sizeof(p)); printf("char point size is :%d\n",sizeof(p1)); printf("float point size is :%d\n",sizeof(p2)); printf("double point size is :%d\n",sizeof(p3)); printf("struct point size is :%d\n",sizeof(p4)); printf("void point size is :%d\n",sizeof(p5)); return 0;}
数组与指针
由于数组中的每一个元素都是变量,因此可以使用指针方式访问数组中的元素。对一个指向数组元素的指针变量的定义和赋值方法,与指针变量相同。
int a[10]; /*定义 a 为包含 10 个整型数据的数组*/int *p; /*定义 p 为指向整型变量的指针*/p=&a[0]; /*把 a[0]元素的地址赋给指针变量 p*/
C 语言规定,数组名代表数组的首地址,也就是第 0 号元素的地址。因此:
p=a; /*等价于 p=&a[0]; */int *p=a; /*等价于 int *p=&a[0]; */
对于执行首地址值的指针,
p+i
就是第
i
个元素的地址值,而
*(p+i)
或
*(a+i)
就是第
i
个元素的值。
引入指针变量后,就可以用以下两种方法来访问数组元素:
(1)下标法:即用
a[i]
形式访问数组元素。
(2)指针法:即用
*(p+i)
或
*(a+i)
形式,用间接访问的方法来访问数组元素。
#include<stdio.h>int main(){ int i; int a[10]={1,2,3,4,5,6,7,8,9,0}; int *p=a; for(i=0;i<10;i++) { printf("P Value:%d a Value :%d\n",*(p++),*(a+i)); } printf("\n"); return 0;}
字符串与指针
可以用字符串常量对字符指针进行初始化
char *str = "www.dotcpp.com" ;char string[ ] = "Welcome to dotcpp.com";
这是对字符指针进行初始化。此时,字符指针指向一个字符串常量的首地址。
字符串指针和字符串数组两种方式都可以访问字符串,但它们有着本质的区别:
字符指针
str
是个变量,可以改变
str
使它指向不同的字符串, 但不能改变
str
所指向的字符串常量的值。 而
string
是一个数组,可以改变数组中保存的内容
。
指针变量不能改变字符的值,只能改变地址值,而数组可以改变字符串的值。
#include<stdio.h>int main(){ char *str = "www.dotcpp.com"; char string[]="Welcome to dotcpp.com"; str[0]='C'; //试图修改str指向的常量区的字符串内容 return 0;}
复合结构
结构体的定义和使用
结构体就像
java
中类的概念,另外结构体的定义说明了它的组成成员,以及每个成员的数据类型。定义一般形式如下:
struct 结构类型名 { 数据类型 成员名 1; 数据类型 成员名 2; ...... 数据类型 成员名 n; };
和其他类型的变量一样,结构变量也可以进行初始化。结构初始化的一般形式如下:
struct 结构类型名 结构变量 = { 初始化数据 1, ...... 初始化数据 n };
#include<stdio.h> #include<string.h> struct _INFO { int num; char str[256]; }; int main() { struct _INFO A; A.num = 2014; strcpy(A.str,"Welcome to dotcpp.com"); printf("This year is %d %s\n",A.num,A.str); return 0; }
结构体的高级使用
指向结构体变量的的指针叫做结构体指针变量,结构体指针变量中的值是所指向的结构变量的首地址,通过结构指针即可访问该结构变量.
体指针变量定义的一般形式为:
struct
结构类型名 *结构指针变量名
共用体的定义和使用
将不同类型的变量存储到同一个内存单元中,这几个变量共同占用同一段内存结构,这种结构称为共用体
union
。共用体的一般定义 形式为:
union 共用体名 { 数据类型 成员名 1; 数据类型 成员名 2; ...... 数据类型 成员名 n; }变量名表列;
只有先定义了共用体变量,才能在后续的程序中引用它。不能直接引用共用体变量,而只能引用共用
体变量中的成员。引用方法如下:
共用体变量名.成员名
共用体变量中起作用的成员是最后一次存放的成员,在存入一个新成员后,原有成员就失去作用。 共用体变量的地址和它的各成员的地址都是同一地址。
#include<stdio.h>union INFO{ int a; int b; int c;};int main(){ union INFO A; A.a=1; A.b=2; A.c=3; printf("a:%d\n",A.a); printf("b:%d\n",A.b); printf("c:%d\n",A.c); return 0;}
不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,并且,不能在定义共用体变量时对 它进行初始化。
不能把共用体变量作为函数参数, 也不能是函数返回共用体变量, 但可以使用指向共用体变量的指针。 共用体类型可以出现在结构体类型的定义中,也可以定义共用体数组。反之,结构体也可以出现在共 用体类型的定义中,数组也可以作为共用体的成员。
使用typedef定义类型
在C语言中,除了结构体和共用体这种自定义的数据类型外,还可以类型说明语句 typedef 定义新的类型来代替已有的类型。typedef 语句的一般形式是:
typedef 已定义的类型 新的类型;
typedef int INTEGER; /*指定用 INTEGER 代表 int 类型*/typedef float REAL; /*指定用 REAL 代表 float 类型*/
在具有上述 typedef 语句的程序中,下列语句就是等价的:
int i, j; /*与 INTEGER i, j;*/float pi; /*与 REAL pi;*/
类型说明语句
typeof
的最常用的作用是给结构体变量重命名
#include<stdio.h>#include<string.h>typedef struct _INFO{ int num; char str[256];}INFO;int main(){ struct _INFO A; INFO B; //通过typedef重命名后的名字INFO与struct _INFO完全等价! A.num = 2014; strcpy(A.str,"Welcome to dotcpp.com"); B=A; printf("This year is %d %s\n",A.num,A.str); printf("This year is %d %s\n",B.num,B.str); return 0;}
可以看到typedef可以为关键词改名,使改名之后的INFO类型等价于
struct _INFO
类型,让我们在定义这种结构类型时更方便、省事。
文件操作
C语言实现文件读写
C语言中所定义的变量都是存储在内存中的,内存中的数据关机就会消失。那C语言是如何读取磁盘中的文件的呢?C语言读写磁盘中的文件一般有3个步骤:
1.打开文件
2.读写文件
3.关闭文件。
其中上面每一步操作都需要通过函数所提供的接口来实现。打开文件所使用的函数是
fopen
函数,读写文件所使用的函数是
fprintf
、
fscanf
或者
fwrite
、
fread
或者
fputs
、
getss
,每组函数都是写和读文件。
fprintf
和
fscanf
的作用是向文件中输入和输出。
关闭文件所使用的函数是
fclose
函数,它的作用是切断文件指针和文件的关联。如果未关闭文件,就对文件进行读写操作,则会出现“正在被使用,无法修改”的提示。
打开文件
fopen
函数的用法
fopen
fopen
函数的作用是打开文件,获取文件指针。函数原型是:
FILE *fopen(const char *filename, const char *mode);
该函数的两个参数是字符类型的文件名和字符类型的文件操作模式,函数的返回值是FILE类型的文件指针,打开失败则返回NULL。以下是常见的文件操作模式。
FILE结构体类型的定义如下:
typedef struct { int level; /* fill/empty level of buffer */ unsigned flags; /* File status flags */ char fd; /* File descriptor */ unsigned char hold; /* Ungetc char if no buffer */ int bsize; /* Buffer size */ unsigned char _FAR *buffer; /* Data transfer buffer */ unsigned char _FAR *curp; /* Current active pointer */ unsigned istemp; /* Temporary file indicator */ short token; /* Used for validity checking */ } FILE;
比如,如果我们现在想打开一个D盘根目录下的
123.txt
,并且想读出该文件里的数据,那么我们可以这样写:
FILE *fp;fp=fopen("d:\\abc.dat","r")//后面通过fp指针开始读文件
值得说明的是
1.文件路径可以是绝对路径,也可以是相对路径,该文件的目录是绝对路径,因此这样写,如果不写盘符比如
abc.dat
则表示相对路径,表示与本程序同目录下。
2.路径中的反斜杠虽然只有一个,但这里打了两个,原因在于C语言字符串中对反斜杠要当作转义字符处理,因此要用两个反斜杠才能表示一个。
3.一旦以r也就是只读的方式打开文件,后面则不允许写数据,否则会出错,一定要保持一致!
写文件
fprintf
函数的用法
fprintf
如果打开模式是写,那么可以用
fprintf
函数来进行写,下面来介绍
fprintf
函数,它的原型是:
int fprintf (FILE* stream, const char*format, [argument])
该函数比
printf
函数多了一个参数,该参数是文件指针。该函数的返回值是一个整数,写入成功返回的是写入字符的格式,写入失败返回的是一个负数。以下是常见的格式化字符串类型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VCUN6rIK-1624429938549)(C:\Users\y\AppData\Roaming\Typora\typora-user-images\image-20210621125125286.png)]
读文件
fscanf
函数的用法
fscanf
从文件里读数据所使用的是
fscanf
函数,它的函数原型如下:
int fscanf(FILE *stream, char *format[,argument...]);
第一个参数是文件指针,表示读取的文件目标,其余参数和
scanf
一样,按照相应的格式进行读取,返回值表示读取数据的字节数。比如:
char str[100];fscanf(fp,"%s",str);
上诉代码表示的是从
fp
所指向的文件中进行读数据,与空格或换行结束,将结果保存到
str
数组中。
更多
scanf
的格式如下表:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ROKyJqc0-1624429938550)(C:\Users\y\AppData\Roaming\Typora\typora-user-images\image-20210621125708457.png)]
写文件
fwrite
函数的用法
fwrite
写文件的是
fwrite
函数,它的函数原型如下:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
这个函数的参数有4个:
第一个是写入数据的头指针。
第二个是每个写入元素的大小,单位是字节。
第三个参数是个数。
第四个参数是文件指针,表示往哪里写。
该函数执行成功返回写入元素的个数,写入失败显示错误。
#include<stdio.h> int main (){ FILE *fp; char str[] = "www.123.com"; fp = fopen( "123.txt" , "w" ); fwrite(str, sizeof(str) , 1, fp ); fclose(fp); return(0);}
以上代码的意思是将
str
字符串写入到
123.txt
文件中。
读文件
fread
函数的用法
fread
fread
函数的作用是从文件里读内容到程序中,它的返回值表示读取元素的个数,与
nmemb
一致表示读取成功,否则失败,
fread
函数原型如下:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
这个函数有4个参数:
第一个参数
ptr
表示盛放内容的首地址
第二个参数
size
表示每个元素的大小,单位还是字节
第三个参数
nmem
表示要读取的元素个数
第四个参数
stream
表示的是文件指针,即从哪个文件中读取
#include <stdio.h>#include <string.h> int main(){ FILE *fp; char buffer[100]; /* 首先打开文件,读写都可以,假设文件中已经有内容为www.dotcpp.com */ fp = fopen("dotcpp.dat", "w+"); /* 读取并显示数据 */ fread(buffer, 1, 15, fp); printf("%s\n", buffer); fclose(fp); return(0);}
关闭文件
fclose
函数的用法
fclose
fclose
函数的作用是关闭文件,切断文件指针和文件之间的联系,返回值为整型,成功关闭则返回0,失败则返回-1。它的函数原型如下:
int fclose( FILE *fp );
位运算
位运算
位运算包含<<(左移)、>>(右移)、~(按位取反)、&(按位与)、|(按位或)、^(按位异或) 共六种运算符。
功能如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWeihnlF-1624429938550)(C:\Users\y\AppData\Roaming\Typora\typora-user-images\image-20210621142034533.png)]
移位运算符
<<和>>分别是C语言中的左移和右移运算符,如表达式13<<2,它的运算过程为:13用二进制表示为,0000 0000 0000 0000 0000 0000 0000 1101,那么向左移两位,右侧补0,则变为0000 0000 0000 0000 0000 0000 0011 0100 换成十进制即变为52。
#include<stdio.h>int main(){ int a,b; a=13<<2; b=25>>3; printf("a=%d,b=%d\n",a,b); return 0;}
运行结果如下:
a=52,b=3
移位运算符的作用:
1.左移N位的本质是乘以2的N次方
2.右移N位的本质是除以2的N次方
&按位与运算符
按位与运算符&,它的使用规则是同1则为1,不同1则为0。如3&5,运算过程如下:
3 0000 0000 0000 0000 0000 0000 0000 00115 0000 0000 0000 0000 0000 0000 0000 0101& ------------------------------------------ 0000 0000 0000 0000 0000 0000 0000 0001
#include<stdio.h>int main(){ int a; a=3&5; printf("a=%d\n",a); return 0;}
运行结果如下:
a=1
按位与运算符的作用:
-
清零
我们可以对某一个数与0进行按位与运算,由于两个位都为1才为1,因此最终全部位都变为0,起到清零的作用
-
取指定位
如某些存储场景下,“第1
3位表示xxxx“”,我们需要取出1
3位,则可以让原数值与数字7进行按位与运算,得到的结果即是原数值的1~3位的值。 -
判断奇偶
可以发现,数字的奇偶取决于二进制位的最低一位是1还是0,因此只需要与1按位与运算,判断是1是0即可得知奇偶。
|按位或运算符
|按位或运算符的作用规则是有一个为1结果即为1。如8|7的运算过程可以如下表示:
8 0000 0000 0000 0000 0000 0000 0000 10007 0000 0000 0000 0000 0000 0000 0000 0111& ------------------------------------------ 0000 0000 0000 0000 0000 0000 0000 1111
#include<stdio.h>int main(){ int a; a=8|7; printf("a=%d\n",a); return 0;}
a=15
按位或运算符的作用:
-
对一个数字的指定位,置为1
如“某个数字的第七位”表示开关,原先是0,需要改为1的状态,即可以将这个数字与64按位或,即可得到第七位变为1,其余位的值依旧不变。
^按位异或运算符
^表示按位异或运算符,它的作用规则是不同则为1,反之为0
例如15和16进行异或运算,运算过程如下:
15 0000 0000 0000 0000 0000 0000 0000 111116 0000 0000 0000 0000 0000 0000 0001 0000^ ------------------------------------------ 0000 0000 0000 0000 0000 0000 0001 1111
#include<stdio.h>int main(){ int a; a=15^16; printf("a=%d\n",a); return 0;}
运算结果为:
a=31
异或运算符的作用:
-
指定位数的翻转
如想对某个数字的低4位进行翻转,则可以将这个数字与15(二进制为00001111)进行按位异或运算,既可以将原数字的低四位进行翻转,即高四位不变,低四位0变1,1变0
-
与0异或还是原值
大家可以自行实验,一个数字与0进行异或,结果还是原值
-
交换两个数字
除了之前我们学习交换两个数字需要第三个变量做中介之外,如今可以通过异或运算进行,代码如下:
#include<stdio.h>int swap(int *a,int *b){ if (*a!=*b) { *a=*a^*b; *b=*b^*a; *a=*a^*b; } return 0;}int main(){ int a=5; int b=5; swap(&a,&b); printf("a=%d b=%d\n",a,b); return 0;}
可以看到原先a为3,b为5,运行后得出:
a=5 b=5
~取反运算符
~取反运算符,是对数值的二进制位进行取反,它的作用规则是0变为1,1变为0。
~1=0~0=1
#include<stdio.h>int main(){ unsigned int a=1; printf("~a=%u\n",~a); return 0;}
运算结果如下:
~a=4294967294