一、C数据类型及语句
1、C语言的程序框架
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
//用户自己的代码
return 0;
}
1)头文件说明
#include //头文件----包含一些函数的声明,或者说是一些数据类型的声明。C语言中用 一个东西用之前必须要先有(声明,定义)
#include "xxxx.h" //自己写的头文件用”"包含
2、C语言的注释
1)单行注释 //
2)批量注释代码 /* 注释的内容 */ 注意:/*和*/是就近匹配原则
3)批量注释代码
#if 0
注释的代码内容
#endif
int main(int arg,char * argv[])
{
//自己写的代码
#if 0
//如果#if 后面跟的是0 表示#if 0 到#endif之间的内容为注释,如果#if后面跟的是1,表示#if 1到#endif
//之间的内容为代码内容
printf("%s","you are my world\n");
printf("%s","you are my world\n");
#if 1
printf("%s","you are my world\n");
printf("%s","you are my world\n");
#endif
printf("%s","you are my world\n");
#endif
printf("%s","you are my world\n");
printf("%s","you are my world\n");
printf("%s","you are my world\n");
printf("%s","you are my world\n");
printf("%s","you are my world\n");
return 0;
}
3、程序的编译过程
编译的4个过程:
1) 预处理 会将头文件、宏原地展开,去掉注释
2) 编译 将.i的预处理文件编译成汇编文件
3) 汇编 汇编将汇编文件转换成二进制文件
4)链接 将各个函数的二进制文件按照规则组织起来
预编译:
gcc -E xx.c -o xx.i //.i是预处理文件
编译:
gcc -S xx.i -o xx.s //.s是汇编文件
汇编:(只编译,不连接)
gcc -c xx.s -o xx.o //.o是二进制文件
链接:
gcc xx.o -o xx.out //.out是可执行文件
参数:
-o 指定输出可执行程序的名字
-Wall 编译优化,语法的严格检查
-I 后面跟头文件的路径,说明头文件查找的路径(大写的i)
-lxxx 说明程序编译链接的库名
-L 添加三方库的路径
gcc xxx.c xxx.c -o 输出程序名字
程序的执行:
./可执行程序的名字
4、关键字
1、关键字的定义
用来表示特定内容的,特定语法的符号,一般C语言里面有32关键字,分别表示存储类型、数据类型、控制语句、以及其他。
2、存储类型关键字
auto static extern register const volatile
主要去说明数据存储在什么位置,或者限定变量或者函数作用的范围 (能作用在哪个文件)
3、数据类型关键字
char:单字节整型数或字符型数 short:短整型数 int:基本整型数 long:长整型数
float:单精度浮点型数 double:双精度浮点型数 signed:有符号数(默认的就是有符号) unsigned:无符号数数据
void:无数据类型、空数据类型 typedef:重新进行数据类型定义
struct:结构体类型数据 enum:枚举类型数据 union:联合类型数据
主要说明,修饰的符号(一般都是修饰变量的),内存分配分配多大。
4、控制语句的关键字
if:构成选择语句 else:构成选择语句 switch:构成选择语句 case:构成选择语句
break:跳出最内层循环 default:构成选择语句 for:构成循环语句
do:构成循环语句 while:构成循环语句 continue:转向下一次循环
goto:无条件转移语句 return:函数返回
5、其他的
sizeof
5、用户标识符
用来表示一些自己想表示的内容的一些符号。比如说后面变量的命名。比如说我想在程序中表示成绩,可以用socre这样的一些符号等等。
用户标识符定义:
1)以数字字母下划线组成
2)不能以数字打头
3)不能和关键字重名
VOid void a A A8 A_8 9A _A IF if
注:在C语言里面区分大小写
6、常量
常量一般是指一些固定的不能变化的量,在程序语言中可以体现为数值(eg:1,2,3,4,5......),也可以是字符常量(eg:'a','b','c'.....),也可以是字符串常量("hello world","hahahhahah",......)
1、数值常量
数值型常量在C语言中除了用十进制表示之外,还可以用二进制,八进制和十六进制来进行表示。当然对于数值来说,我们还分为:整数、浮点数(小数)、正数、负数等等
2、正整形数值的表示方法
正整数在C语言中通常使用十进制、二进制、八进制、十六进制进行表示
3、各种进制数据的表示
1、二进制(0~1)
满2进1,在计算机中使用的比较多。二进制以0b开头,在二进制中不能有超过2的数据值
eg:0b110 0b01110
2、八进制(0~7)
满8进1,在计算机中八进制以0开头,在八进制的数据中不能有超过8的数据值
eg:0134
3、十进制(0~9)
满10进1,我们生活中常见的数据值就是10进制的,生活中怎么表示的,计算机中就怎么表示
eg:11 12
4、十六进制(0~F)
满16进1。在计算机中十六进制以0x开头 (A---10 B--11 C--12 D--13 E---14 F--15)
eg:0x3344
4、进制的转换
1、 二进制转换十进制:
每位的数据值*位权值进行加和得到。
2、十进制转二进制
3、八进制转十进制
方法和二进制转换一样
4、十进制转8进制
方法和二进制差不多,除8倒取余,直到商为0
5、十六进制和二进制之间的转换
十六进制和十进制的转换参照二进制(略),我们主要研究和二进制的转换。
一个十六进制位代表4个二进制位。
5、正整形数值在内存中的存储方式
大端存储模式:(0x12345678)
高字节存储在低地址上,低字节存储在高地址上
小端存储模式(Linux):
高字节存储在高地址上,低字节存储在低地址上
6、负整形数值在内存中的存储方式
负数,最高位表示符号位,符号位为1表示负数。在C语言中表达的时候,只需要在正数前添加负号即可。在内存中存储的时候,存储的是补码。
补码得到的方式:
源码:在正数的基础上添加符号位
反码:对源码按位取反得到反码(注意符号位不变)
补码:对反码+1得到补码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
int a = -18;
printf("---%u\n",a);
printf("-- %d\n",a)
printf("%u\n",-18);
printf("%d\n",-18);
return 0;
}
7、小数
小数在C语言中的表现形式: xx.xx 1.3
科学计数法: 1e-3 表示1*10^-3
1.3f 表示单精度浮点数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
printf("%f\n",1.3);
printf("%f\n",13e-1);
return 0;
}
8、字符常量
1、单个字符常量
单个字符常量用单引号引起来
eg:
‘a' 'c' '1' 'abc'(错误的,单引号中只能是单个字符)
2、多个字符常量(字符串常量)
多个字符用双引号引起来
eg:
"hello" "world"
注意的是:
一般来说一个字符占一个字节,在内存中存的时候字符串中多包含一个'\0',即存储时要多开辟一个字符的内存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
char a='a';
printf("%c\n",'a');
printf("%ld\n",sizeof(a));
printf("%s\n","hello");
printf("%ld\n",sizeof("hello"));
return 0;
}
3、字符及字符串在内存中存储的方式
字符在内存中以ASCII码值的形式存储
man ASCII
对于我们需要记住的是:
’0‘ -------48
’a'---------97
'A' --------65
空格 --------32
0 '\0' NULL '0'的区别
((void *) 0)
4、转义字符
1、常见的转义字符:
'\t' ----table键 '\n' 换行 '\0' -------ASCII码值0 ‘\r' 回到首行符号 '\a' 发出警报
2、八进制的转义:
'\ddd' 每个d的取值范围是0-7 这里只能有3个数据位
eg:以下字符描述正确的是:
A: '\123' B :'\18' C:'\1234' D:'\183'
3、十六进制的转义:
'\xhh' 每个h的范围是0~9或者是a~f 这里只能有2位十六进制
eg:以下字符描述正确的是
A:'\af' B:'\123' C:'\x3df' D:'\xab'
5、拓展
printf 的格式输出符号
形式:printf("格式控制符1 格式控制符2....",1的匹配变量/常量,2的匹配变量/常量...)
%d 十进制有符号整数 %u 十进制无符号整数
%x, 以十六进制表示的整数 %o 以八进制表示的整数
%f float 型浮点数
%lf double 型浮点数
%e 指数形式的浮点数
%s 字符串
%c 单个字符
%p 指针的值
特殊应用:
%3d
%03d
%-3d
%5.2f
%3d:要求宽度为 3 位,如果不足 3 位,前面空格补齐;如果足够 3 位,此语句无效
%03d:要求宽度为 3 位,如果不足 3 位,前面 0 补齐;如果足够 3 位,此语句无效
%-3d: 要求宽度为 3 位,如果不足 3 位,后面空格补齐;如果足够 3 位,此语句无效
%.2f:小数点后只保留 2 位
9、变量
在C语言中,有些符号需要去表示我们想表示的内容,但这些内容的数据值在程序运行的过程中可能会发生变化,这样的符号我们叫做变量。
1、变量的定义
变量的本质就是一片内存空间
存储类型 数据类型 变量;
2、修饰变量的存储类型
1、auto:
一般定义变量的时候,是省略的。自动存储类型,如果变量是局部变量,变量的内存分配就在栈内存中,如果是全局变量,变量的内存分配就在数据段。
2、 static:
1)修饰局部变量,内存分配在数据段,延长变量的生命周期
2)修饰全局变量,限制该全局变量在定义的文件中使用,别的文件不能使用
3)修饰函数,限制函数只能在定义文件中使用
3、 extern:
作用:主要是用来声明变量或者函数的。
声明变量:
一般extern声明的变量,定义在别的文件,在所要使用的文件中添加声明,添加的位置一般在头文中或者使用该变量文件的头文件下面
extern 数据类型 变量名;
4、 register:
想将变量定义在CPU的寄存器中,但是不一定能实现,如果CPU的寄存器有空余的,就定义,没有就按auto这种存储类型来处理。
5、const:
const修饰的变量认为一个常量(不是说明变量存储在哪),而是变量不应该修改值
6、volatile:
一般是修饰易变的变量,作用是告诉编译器不要优化程序
7、sizeof :
主要是用来求数据类型,或者常量,变量的内存大小的。
注意:在进行变量赋值的时候,一定要注意数据类型表示的范围,数据有没有溢出。
3、变量的分类
全局变量:
定义在一对花括号外面的就是全局变量。在整个程序运行的过程中都有效(作用域:作用范围,程序任何地方都可以访问。生命周期:程序结束的时候)
局部变量:
定义在一对花括号里面的叫做局部变量。局部变量作用于所定义的花括号内部,出了定义的花括号就消亡了。
注意:
1)在同一个作用范围内,变量一般不能重名
2)如果全局变量和局部变量同名,在局部范围内,局部量说了算。出了局部范围,局部变量不存在,同名的全局变量说了算
4、修饰变量的数据类型
数据类似主要说明:
1)变量定义的时候开辟内存空间开辟多大
2)变量所存放的数据,限制数据的范围
3)解析数据的时候,按照什么样的格式进行解析
eg:
unsigned char: 占1个字节 0-255 0-2^8-1
unsigned char a = 256;
unsigned int: 占4个字节 0-2^32-1
unsigned short: 占两个字节 0-2^16-1
5、常见数据类型定义变量举例
1、char 用来修饰字符变量
char 字符型 ,用 char 定义的变量是字符型变量,占 1 个字节
char ch='a'; =为赋值号
char ch1= ‘1’; 正确
char ch2 = ‘1234’ ; 错误的
2、short 短整型 ,使用 short 定义的变量是短整型变量,占 2 个字节
short int a=11; -32768 - ---32767
3、 int 整型 ,用 int 定义的变量是整型变量,在 32 位系统下占 4 个字节,在 16 平台下占 2 个字节
int a=44; -20 亿---20 亿
4、 long 长整型 用 long 定义的变量是长整型的,在 32 位系统下占 4 个字节
long int a=66;
5、 float 单浮点型 (实数),用 float 定义的变量是单浮点型的实数,占 4 个字节
float b=3.8f;
6、 double 双浮点型 (实数),用 double 定义的变量是双浮点型的实数,占 8 个字节
double b=3.8;
7、signed 有符号(正负)的意思
在定义 char 、整型(short 、int、long) 数据的时候用 signed 修饰,代表咱们定义的数据是有符号的,可以
保存正数,也可以保存负数
例 :signed int a=10;
signed int b=-6;
注意:默认情况下 signed 可以省略 即 int a=-10;//默认 a 就是有符号类型的数据
8、unsigned 无符号的意思
在定义 char 、整型(short 、int、long) 数据的时候用 unsigned 修饰,代表咱们定义的数据是无符号类型的
数据只能保存正数和 0。
unsigned int a=101;
unsigned int a=-101; //错误
9、void 空类型的关键字
char、int 、float 都可以定义变量
void 不能定义变量,没有 void 类型的变量
void 是用来修饰函数的参数或者返回值,代表函数没有参数或没有返回值
例:
void fun(void)
{
}
10、typedef 重命名相关的关键字
关键字 ,作用是给一个已有的类型,重新起个类型名,并没有创造一个新的类型
用法:
typedef 原有数据类型 数据类型别名;
拓展:
批量定义变量:
数据类型 变量名1,变量名2;
数据类型 变量名1=变量值,变量名2=变量值;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
float a= 3.3, b=4.4;
printf("%.2f %.2f\n",a,b);
return 0;
}
10、强制类型转换
一个变量可能是一种数据类型的,现在我需要按照其它的数据类型来进行解析这片内存。
表现形式:
(强转的数据类型)变量的名
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
int a = 0x12345678;
printf("%d\n",(unsigned char)a);
return 0;
}
11、隐式类型转换
1、什么是隐式类型转换
在进行一些算数混合运算的时候,操作数是不同数据类型的时候,数据类型会发生自动转换的问题。这种就叫做隐式类型转换
2、转换的原则
字节内存小的向字节内存大的去转,数据范围小的向数据范围大的转,单精度的向双精度转
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
int a = 5;
int b = 2;
float c =a/b; //数据类型相同,/表示整除
printf("%.2f\n",c);
float d = 2.0;
c = a/d; //2.5
printf("%.2f\n",c);
return 0;
}
12、运算符
1、运算符分类
根据操作数的数量(这的操作数指操作的变量),分为单目运算、双目运算、三目运算
2、算数运算符
+ - * / % += -= *= /= %=
% 取余数
/ 如果操作数中没有小数的话一般是整除
+= 注意符号与符号中间没有空格 eg: a += b; a=a+b;
3、关系运算符
(>、<、= =、>=、、!= )
!=为不等于
一般用于判断条件是否满足或者循环语句
a大于100 小300
数学里面: 300> a>100(程序中不能这样写)
程序里面:a>100 && a
4、逻辑运算符
逻辑判断中,真是非0值,假是0值
1、&& 逻辑与
两个条件都为真,则结果为真,两个条件中有一个条件为假,结果即为假。
if((a>b) && (a
if(b这种表达方式是错误的
注:短择情况
if(表达式1 && 表达式2)
{
}
如果表达式1为假了,表达式2就不会判断执行
eg:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
int a = 1;
int b = 1;
if((--a) && (b++))
{
printf("ddddddddd\n");
}
printf("%d\n",b);
return 0;
}
2、|| 逻辑或
两个条件至少有一个为真,则结果为真,两个都为假的话,结果为假。
if((a>b) || (a
短则:
如果第一个表达式为真,后面的表达式就不会执行
3、! 逻辑非
对表达式的结果取反
if(!(a>b))
{
}
5、位运算符
1、& 按位与
操作数1 & 操作数2,将操作数转换成二进制位,进行按位与
2、 | 按位或
操作数1 | 操作数2,将操作数转换成二进制位,进行按位或
3、~ 按位取反
对每一位进行取反。
4、^异或
题目: 两个变量进行交换,不引入第三个变量。
int a = 0x12,b=0x13;
int temp = a;
a = b;
b = temp;
异或方式:
a = a^b; //0b 0001 0010 ^ 0b0001 0011-------0000 0001
b = a^b; //0000 0001 ^ 0b0001 0011 ------>0001 0010
a = a^b; //0000 0001 ^ 0001 0010 -------0001 0011
5、左移
6、>>右移
>>右移分为算术右移和逻辑右移
对逻辑右移:不管是正数还是负数都是左边补0,右边移出去的丢弃掉
对于算数右移:左边移动的位补符号位,右边移出去的丢失掉
(算术右移、逻辑右移 都是编译器决定,用户无法确定。 无符号数:右边丢弃 左边补0 有符号数: 正数:右边丢弃 左边补0负数:右边丢弃 左边补0(逻辑右移) 负数:右边丢弃 左边补1(算术右移))
证明:Linux中gcc使用的是算数右移
#include
#include
#include
int main(int arg,char * argv[])
{
char a = 0b10101011;
//1)注意赋值符号不管原码反码和补码,只管存储数据,等号的右边数据是什么,他就存储什么
//2)定义一个变量的时候如果没有说明这个变量是无符号的,那么这个变量就是有符号的
//对于该题,内存中存储的是:10101011---->说明它是补码----》10101010(反码)----》01010101--->1+4+16+64=85--->-85
printf("%d\n",a>>1); //-43 0010 1011---->1101 0100-->1101 0101
return 0;
}
执行结果:
edu@edu:/mnt/hgfs/Share/2401/C_Basic/cal_character$ ./a.out
-43
7、综合应用
1、对某一个数中的某些bit位进行清零
char a = 0xff; //bit2进行清零 0b1111 1111
a &= ~(10b1111 1011
练习:
a=0x99 的bit3清零 a &= ~(1 a=0xf4 的bit5清零 a &=~(1 a = 0x11的bit4和bit0清零 a &= ~((1 a= 0xffff 对bit13 和bit10进行清零 a &= ~((1 a=0xf56f 对bit12和bit3及bit2进行清零 a &= ~((1总结: a&= ~( 1
2、对某一个数中的某些bit位进行置1
总结:如果是对一个数(变量)的某些位进行置1,只需要这个数(变量)1=1a |= 1
6、三目运算符
表达式1?表达式2:表达式3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
int a = 10;
int b = 5;
int c = 0;
scanf("%d%d",&a,&b);
c = (a>b)?(a):(b);
printf("%d\n",c);
return 0;
}
7、逗号表达式
(表达式1,表达式2) 逗号运算中一般整体表达式的结果取最后一个表达式的结果
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arg,char * argv[])
{
int a = 1;
int b = 2;
int c = (a++,++b);
printf("%d %d %d\n",a,b,c);
return 0;
}
8、算数运算优先级
注意所有运算符号都是有优先级的,这就要求我们写代码的时候需要注意,一般解决方法不是靠记忆,靠的的是加括号,你想要什么先运算就把它们先括起来。