由于非计算机专业毕业的,压根不知道该怎么学习编程。不妨把编程当数学来学。所以从下面几个方面来学习编程:常量、变量、运算、关系、命令。由于常量不变,没什么好学的。就从变量开始。
一、变量
【1】定义
定义方式:存储类型 数据类型 变量名;
1)所谓“存储类型”,其实就像我们存钱一样,有专款专用的钱、有日常开销的钱、也有储备金。。。不同的存储类型,代表着不同的存储位置、不同的作用域。只有设定好了存储类型,计算机在你需要用的时候,才知道拿哪部分数据给你。C语言一般把存储类型为六大类:const static extern volatile auto register auto 。在日常写代码的过程中存储类型auto 一般省略
const:使用const定义的变量,在程序运行的该过程中值不能被修改
static:定义静态变量
extern:引入外部文件中的变量
register:在寄存器中定义变量,不一定会申请成功
volatile:防止代码优化,每一次都从内存中取变量的值
auto:自动变量,不写存储类型局部变量默认是auto
2)所谓的“数据类型”,如同我们平常的用钱的形式,例如:可以是支票、现金、余额宝等,都是钱。C语言的数据类型,主要有:整型、浮点型、字符型、数组、结构体、共用体、枚举型。
3)所谓的“变量名”,其实就是标识符,如同人的名字。人没名字,对方就不知道你在呼唤他;变量如果没有名字,程序就不知道你需要调用谁。C语言对变量名是有一定要求的:
a.可以由数字、字母和下划线构成
b.不能以数字开头。例如,变量名不能为 1abcd
c.严格区分大小写。例如,变量abcd1 与 abcD1 是两个不同变量
d.不能和C语言的32个关键字重复。例如不能有以下这些关键字:
数据类型相关的:int double float long short char struct union typedef enum
存储类型相关的:const static extern register volatile auto
结构相关的:for while do case switch if else goto
辅助控制关键字:break continue default return
其他关键字:sizeof
【2】变量的初始化和赋值
初始化,在定义的直接给初始值
赋值,先定义后赋值
使用变量前,一定要确保变量已经赋值过。例如:
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a; //定义了一个整形的变量a,没有初始化,存的是随机值
printf("a=%d\n",a); //错误。a没有初始值。但现在的编辑器一般认定为0
int num = 10; //定义了一个整形变量num初始化为10
printf("num=%d\n",num);
a = 100; //给a赋值为100
printf("a=%d\n",a);
int num1 = num; //使用已有的变量num给num1初始化
printf("num1=%d\n",num1);
num1 = a; //使用已有的变量a给num1赋值
printf("num1=%d\n",num1);
int num1,num2,num3,num4; //定义了四个整形变量num1、2、3、4
return 0;
}
【3】类型转换
大的数据类型转小的数据类型是不安全的
小的数据类型转大的数据类型是安全的
i)隐式的强制类型转换
转换的过程是编译器做的,
#include <stdio.h>
int main(int argc, const char *argv[])
{
char c = 'a';
int num = c; //隐式的强制类型转换,把c变量的ascii赋值给int类型的数据
//char 1Byte int 4Byte 小的数据类型向大的数据类型转换
printf("%d\n",num);
//signed定义有符号数 unsigned定义无符号数
unsigned int num1 = 0xFFFFFFFF; //给四个字节中的每个bit都置1
//unsigned int num1 = 0xFF113478;
//0b 1111 1111 0001 0001 0011 0100 0111 1000
//把10行的num1转换成short=0x3478;
//unsigned int num1 = 0x11111111;
//unsigned char a = num1;
printf("%u\n",num1); //4294967295
unsigned short int num2 = num1;
printf("%u\n",num2); //65535
//int 4Byte short 2Byte
//大的数据类型向小的数据类型强转的时候,会发生数据的丢失,不安全的
return 0;
}
ii)显式强转
格式:(强转的目标类型)强转的数据;
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned int num = 0xFFFFFFFF;
unsigned short int num1 = (short)num;‘‘
unsigned char a = (char)num;
//显式的强制类型转换,可以看见强转的过程
//把int类型的num强转为short类型
//(强转的目标类型)强转的内容; 通常强转的结果会用对应的数据类型接收
printf("%#X\n",a); //0xFF,输出一个字节
printf("%#X\n",num1); //0xFFFF
return 0;
}
iii)有符号和无符号数之间的转换
隐式的强制类型转换,无符号数和有符号数一起运算,强转成无符号数
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned int c = 2; //无符号数
signed int a = -3; //有符号数
printf("%u\n",a+c); //隐式的强制类型转换,无符号数和有符号数一起运算,强转成无符号数
if(a+c>0)
{
printf("1\n");
}
return 0;
}
【4】变量的取值范围
有符号数signed、无符号数unsigned
默认都是有符号数
根据数据的最高位是符号位,0表示是正数,1表示负数
原码、反码和补码
计算机中,数据都是以补码的形式进行存储和运算。
都是二进制表示的
原码:人能看懂的,十进制转换过来的
反码:原码和补码的一个中间状态 ,正数原码、反码和补码都一样,负数,原码的除符号位外其他位取反
补码:计算机中存储和运算用的都是补码,正数原码、反码和补码都一样,负数的补码是反码+1
正数的原反补都相同
负数的反码是原码除符号位外取反,补码是反码+1
有符号数 -123 +123
原码1111 1011 0111 1011
反码1000 0100 0111 1011
补码1000 0101 0111 1011
i)char 1Byte
无符号数[0,255] ---- [0,2^8-1]
有符号数 [-2^7,2^7-1]
[0000 0000 ----- 0111 1111] ----- [0,2^7-1]
[1111 1111 ----- 1000 0000] ------ [-2^7,0]
1000 0000 ------> 1111 1111 -----> 1 0000 0000 -0的补码 1000 0000 规定 1000 0000是-128的补码,-128没有原码和反码,-128补码的最高位,既是符号位也是数据位。
127 补 0111 1111 + 1 补码0000 0001 = 1000 0000
1 0000 0001
-1 1111 1111
0000 0001
1111 1111
0000 0000
计算机中数据存储的时候看的是数值(有无符号)
取出数据,看类型;
#include <stdio.h>
int main(int argc, const char *argv[])
{
signed char c = 129;
//存储看符号+
//原码:1000 0001
//反码:1000 0001
//补码:1000 0001
//取出看类型:
//补码:1000 0001
//反码:1000 0000
//原码:1111 1111
printf("%d\n",c);
c = 255;
//存储看符号+
//原码:1111 1111
//反码:1111 1111
//补码:1111 1111
//取出看类型
//补码:1111 1111
//反码:1111 1110
//原码:1000 0001
printf("%d\n",c);
unsigned char p = -1;
printf("%u\n",p);
c = 213;
//存储看符号
//原码:1101 0101
//反码:1101 0101
//补码:1101 0101
//取出看类型
//补码:1101 0101
//反码:1101 0100
//原码:1010 1011
printf("%d\n",c);
return 0;
}
ii)short 2Byte 16bit
无符号数[0,2^16-1]
有符号数 [-2^15,2^15-1]
正数[0,2^15-1]
负数[-2^15,0]
1000 0000 0000 0000
iii)int 4Byte 32bit
无符号数[0,2^32-1]
有符号数 [-2^31,2^31-1]
正数[0,2^31-1]
负数[-2^31,0]
1000 0000 0000 0000 0000 0000 0000 0000
补码是通过模运算得来的。
练习:
124,原码、反码和补码0111 1100
-35:1010 0011 -----> 1101 1100 ----->1101 1101
-126:1111 1110 -----> 1000 0001 ------> 1000 0010
-96:1110 0000 ----> 1001 1111 -----> 1010 0000
-24:1001 1000 ------> 1110 0111 ------> 1110 1000
-123:1111 1011 ------> 1000 0100 ------> 1000 0101
-115:1111 0011 ------> 1000 1100 ------> 1000 1101
二、标准输入输出函数
【1】printf
函数原型
int printf(const char *format, ...);
printf使用时,需要一个格式符和一个格式符对应类型的数据
printf("占位符/格式符",输出表象); //有一个格式符就要有一个输出表象
printf("%d\n",10); //10就是输出表象,%d就是10对应的格式符
printf("%c",'c'); //字符c时输出表象,%c是字符c对应的格式符
转义字符,就是有特殊意义的字符
\n:换行 10
\t:制表符 一个tab键的大小4个空格
\b:退格
\r:回车 回退到行首进行输出
\\:输出一个\,键盘上回车上面的\反斜杠,不是除号
格式符
%d:整形数据的格式符
%-nd:以n个数据宽度左对齐输出,不够就补空格
%nd:以n个数据宽度右对齐输出,不够就补空格
%ld:长整型数据的格式符
%f:浮点型的格式符,printf默认输出小数点后6位
%.mf:指定小数点后的输出位数
%lf:双精度浮点型的格式符
%c:字符型的格式符
%s:字符串的格式符
%#x:输出十六进制,并且带前导符0x,小写x,输出十六进制时对应的字母都是小写的
%#X:输出十六进制,并且带前导符0X,大写x,输出十六进制时对应的字母都是大写的
%%: 输出一个%
%u:无符号数输出的格式符
【2】sacnf
函数原型
int scanf(const char *format, ...);
scanf("格式符",变量的地址);
&:取地址符,取变量的地址
scanf以回车作为获取结束的标志,只有缓冲区内的数据>=格式符的个数回车是结束的标志
scanf从缓冲区内获取数据的标志,以空格、tab键和回车作为数据之间间隔的标志
ii)scanf在获取多个字符数据时,需要吸收垃圾字符
#include <stdio.h>
int main(int argc, const char *argv[])
{
//scanf在连续获取多个字符类型数据的时候需要吸收垃圾字符
//因为scanf作为数据分隔的标志,空格,tab和回车都是ascii中能查到的字符
char a,b,c,d;
int num;
//1、利用scanf严格控制格式的特点,%c后面的空格起到吸收垃圾字符的作用
//scanf("%c %c %c %c",&a,&b,&c,&d);
//2、在格式符前面打空格,空格的作用是,吸收输入之前的所有垃圾字符
/*scanf(" %c",&a);
scanf(" %c",&b);
scanf(" %c",&c);
scanf(" %c",&d);*/
//3、使用抑制字符 %*c
//%*c一定要吸收掉一个字符不管字符是否是垃圾字符,不建议使用
//scanf("%c%*c%c%*c%c%*c%c",&a,&b,&c,&d);
//4、使用getchar吸收垃圾字符
scanf("%c",&a);
getchar();
scanf("%c",&b);
getchar();
scanf("%c",&c);
getchar();
scanf("%c",&d);
printf("a=%c\tb=%c\tc=%c\td=%c\n",a,b,c,d);
return 0;
}
【3】字符的输入函数getchar()
getchar()从终端 获取单个字符
getchar(); //语句本身的结果就是从终端获取的字符
char c;
scanf("%c",&c); //通过scanf终端获取c
c=getchar(); //通过getchar终端获取c
【4】字符的输出函数 putchar()
输出单个字符
#include <stdio.h>
int main(int argc, const char *argv[])
{
char c = 97;
putchar(c); //输出单个字符,不会换行
putchar(10); //输出换行
putchar('1');
return 0;
}
三、运算符
【1】算术运算符
运算符作用
+\-\*两数相加、相减、相乘
/如果左右两个操作数都是整形,就是取整运算,结果就是整形
只要有一个操作数是浮点型,结果就是浮点型,除数不能为0
%要求:两个操作数必须是整形,取余,除数不能为0
【2】自增自减运算符
a++,++a,a--,--a
int a = 10; a++或者是a--表达式的结果仍然为10
++a,结果就是11
如果先看见运算符,结果就是运算后的值
如果先看见变量,结果就还是变量本身
练习:
1、使用带参宏实现,两数相乘*,两数相除/,两数模除%
#include <stdio.h>
#define M(a,b) a*b
#define D(a,b) (float)a/b
#define O(a,b) (int)a%(int)b
int main(int argc, const char *argv[])
{
printf("%d\n",M(3,4));
printf("%f\n",D(10,4));
printf("%d\n",O(10.0,4.0));
return 0;
}
【3】赋值运算符
=:赋值运算符
左值 = 右值; 把右值赋值给左值
左值,是既可以作为左值也可以作为右值的量
右值,只能作为右值的量
混合赋值运算符:
a+=1a=a+1
a-=1a=a-1
a*=1a=a*1
a/=2a=a/2
【4】关系运算符
非真即假,非0即1
0假,1真
在C语言中非0即为真
==判断左右两个操作数是否相等
!=不等于
a>b判断a是否大于b
a判断a是否小于b
a>=b判断a是否大于等于b
a<=b判断a是否小于等于b
练习:
1、终端输入两个数,判断两数是否相等
if(表达式成立)
{
执行代码块的内容;
}
2、终端输入一个三位数,输出该数个位+十位+百位的结果
3、终端输入一个四位数,输出该数个位、十位、百位和千位的结果
【5】逻辑运算符
逻辑运算的结果非0即1,非真即假
&&逻辑与,两个操作数都为真结果才是真,
有一个操作数为假结果就是假
||逻辑或,两个操作数都为假结果才是假
一个操作数为真结果就是真
!逻辑非,
逻辑短路现象
逻辑与运算,如果左侧表达式的值为假,右侧的表达式不会执行,逻辑与运算的结果为0/假
逻辑或运算,如果左侧表达式的值为真,右侧的表达式不会执行,逻辑与运算的结果为1/真
练习:
1、终端输入一个数,判断该数是否在区间[12,54]中。a>=12和a<=54同时成立
【6】条件运算符
C语言中的唯一一个三目运算符
表达式1?表达式2:表达式3
先执行表达式1,如果表达式1成立,执行表达式2,如果表达式1不成立,执行表达式3。
练习:
1、终端输入两个数,使用条件运算符,输出两个数中较大的数。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int num,num1;
scanf("%d %d",&num,&num1);
num>num1?printf("%d\n",num):printf("%d\n",num1);
return 0;
}
【7】逗号运算符
(表达式1,表达式2,表达式3·····表达式n)
每个表达式都会执行,取最右侧表达式的结果,
【8】位运算符
一般都使用无符号数进行位运算
对二进制进行运算的
0000 1001 & 0000 1000 =0000 1000 = 8
0000 1001 | 0000 1000 = 0000 1001 = 9
0000 1001 ^ 0000 1000 = 0000 0001 = 1
~0000 1001 = 1111 0110 = 118
0000 1001>>3 = 0000 0001 = 1
0000 1001 << 4 = 1001 0000 = 144
练习:
1、求unsigned char类型数值0x1的数,<<3的结果。
如果没有特殊声明,bit从右向左从0开始,
2、有一个unsigned char类型的数据a,把他的第六个bit位置为1。
a|=(0x1<<6) <==> a = a | 0x1<<6
???? ???? | 0100 0000 0x1<< 6
?1?? ????
3、有一个unsigned char类型的数据a,把他的第六个bit位置为0。
a&=~(0x1<<6)
???? ???? & 1011 1111 ~(0x1<<6)
?0?? ????
位运算常用于对数据的置位操作
0与任何数都是0,1与任何数都是数本身
1或任何数都是1,0或任何数都是数本身
0异或任何数都是数本身,1异或任何数都是取反
已知unsigned char data;写出把data的第三位置1的表达式;
把data的第四位置0的表达式,讲data的第六位按位取反的表达式。^
data|=(0x1<<3);data&=~(0x<<4);data^=(0x1<<6)
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned char data = 0x76; //0111 0110
//0111 0110 | 0000 1000 = 0x7E
//0000 1000 = 0x<<3
//第三位置1:0111 1110 0x7E
data|=(0x1<<3);
printf("%#X\n",data);
//0111 1110 & 1110 1111 = 0x6E
//1110 1111 ~(0x1<<4)
//第四位置0:0110 1110 0x6E
data&=~(0x1<<4);
printf("%#X\n",data);
//两数异或,同0异1
//0异或任何数结果都是数本身,
//1异或任何数都是对该位取反
//0110 1110 ^ 0100 0000
//0100 0000 = 0x1<<6;
//第六位取反:0010 1110 0x2E
data^=(0x1<<6);
printf("%#X\n",data);
return 0;
}
【9】sizeof运算符
sizeof求数据的大小,单位是字节
sizeof(数据); sizeof括号里面放什么,就求什么的大小。
#include <stdio.h>
int main(int argc, const char *argv[])
{
char c = '1';
printf("%ld\n",sizeof(int)); //4
printf("%ld\n",sizeof(short)); //2
printf("%ld\n",sizeof('a')); //4
printf("%ld\n",sizeof(char)); //1
printf("%ld\n",sizeof(c));
return 0;
}
sizeof的结果64为默认是无符号长整型
32位默认是无符号整形
【10】运算符优先级
小知识:
vim可以设置自动补全。方法如下
在家目录下,cd .vim
cd snippets
vim c.snippets
找到main的行,隐藏的使用l打开 ,添加内容,再保存退出
作业:
整理思维导图
有以下变量求输出结果
signed char c = 178;
printf("%d\n",c);
printf("%u\n",c);
unsigned char d = -9;
printf("%d\n",d);
printf("%u\n",d);
并写出数据存储和取出的过程
求-57的原码、反码和补码
-57的原码:1000 0000 0000 0000 0000 0000 0011 1001
反码:0x FF FF FF C6
补码:0x FF FF FF C7