出现警告:警告还是会生成可执行文件,一般的警告可以忽略不管,但是能处理的还是要处理
出现错误:出现错误就不会生成可执行文件,必须要处理,可以根据出错的行数找到出错的位置,一般就是在这一行的上下行出现问题了。
一 第一个c程序简单讲解
1.1 代码注释
方式1:注释一行 //.... 方式2:注释多行 /* ... */ 方式3:注释很多 (#if 0关闭1开启该行功能 #if 0 ... #endif
1.2 中英文切换
ctrl + space
1.3 代码讲解
// #:预处理指令,在gcc编译的第一个阶段就会执行的东西 // #include :要包含的头文件,要使用哪个函数,就需要包含声明所在的头文件 // <>:用来包含头文件,也可以使用"" <>yu""区别:自己写的头文件只能用"" // stdio.h:标准输入输出头文件,printf函数就是在这个头文件中声明的 #include <stdio.h> //int:整数类型,放在这里代表函数的返回值类型 //main:函数名,主函数,是所有函数的入口函数,一个程序只能有一个主函数,而且必须有 //():里面存放参数 //{}:用来包含这个函数的代码(函数体) //函数中每一行代码执行的末尾必须加上; int main(int argc,char *argv[]) { //printf:向终端格式化输出内容(此处为字符串) //\n:换行 printf("hello world!\n"); //return:返回值,返回函数执行的结果 //0:返回的值,这个值的类型与返回值类型一致 //main函数里面返回0实际上是告诉linux内核这个程序执行完毕了 return 0; }
1.4 gcc编译出现问题的解决方式
正确编译:编译完成后没有任何现象
出现警告:警告还是会生成可执行文件,一般的警告可以忽略不管,但是能处理的还是要处理
出现错误:出现错误就不会生成可执行文件,必须要处理,可以根据出错的行数找到出错的位置,一般就是在这一行的上下行出现问题了。
少加分号,会提示哪一行出问题了:
标点符号使用中文会报错:
报错特别多找第一个
二 计算机的数据表示
分类: 数值型数据 非数值型数据
2.1 数值型数据
数值型数据的表示方法:二进制,十进制,八进制,十六进制
代码中前导符是#
[1] 二进制
由0和1表示的数据称之为二进制数据,使用前导符0b
例如:0b1001101001
[2]十进制
由0-9表示的数据称之为十进制数,我们人类所识别的就是十进制数
例如:256 二进制转十进制: 0b11011 --->1*2^0 + 1*2^1 + 0*2^2 + 1*2^3+1*2^4 = 27 十进制转二进制 凑数或这除商取余倒着往上数
[3] 八进制
由0-7组成的数称之为八进制数,使用0作为前导符
例如:0756 八进制转十进制: 0627:--->7*8^0 + 2*8^1 + 6*8^2 = 407 八进制转二进制:一位八进制用三位二进制表示 0627:--->0b110010111 二进制转八进制:将二进制从右往左每三位转化位八进制 0b 10 100 010 001 110 -->024216
[4] 十六进制
由0-9和a-f组成的数称之为十六进制数,使用0x作为前导符
例如:0xa6bd 十六进制转十进制: 0xa6bd --->13*16^0 + 11*16^1 + 6*16^2 + 10 *16^3 十六进制转二进制:一位十六进制数用四位二进制来表示 0xa6bd --->0b1010011010111101 二进制转十六进制:从右往左取四位转为十六进制 0b 0001 1001 0010 0110--->0x1926
2.2 非数值型数据
理论上,非数值型数据计算机时不能识别的,因为计算机只能识别二进制码,也就是数值型数据,但是在写代码的过程中,还需要非数值型数据,所以别人就规定了,每一个非数值型数据都会用一个数值型数据来表示,表示方法称之为ascii,我们将非数值型数据也称之为字符。
使用man ascii可以查询 '\0':----> 0 '\n':---->10 '0' - '9':----> 48 - 57 'A' - 'Z':----> 65 - 90 'a' - 'z':----> 97 - 122
三 词法符号
任何高级语言都有自定义的词法符号和支持的数据类型,词法符号是语言的基本组成单位,数据类型是数据的基本属性,词法符号是程序设计语言中有若干个字符组成的有意义的最小语法单位,按照词法符号在冲虚中的作用:
可分为:关键词,标识符,分隔符,运算符和标点符号,词法符号但凡涉及单词,严格区分大小写。
3.1 关键词
关键词是由系统预定义的词法符号,有特定的含义,不允许用户重新定义,必须都是小写,可以直接使用
char short int long float double enum struct union void signed unsigend 12个 auto register const static volatile extern 6个 typedef 1个 sizeof 1个 if else switch case default for while do goto return break continue 12个
3.2 标识符
标识符就是给代码中一些常用的东西取名字,例如:变量名,函数名, 结构体名,宏定义名,取别名,且这些名字最好与要表示的东西的含义一样。
标识符的命令规则: 只能由数字,字母,下划线(_)组成 第一个字符不能是数字 不能与关键词相同 注:c语言中,关键词和标识符都严格区分大小写
3.3 分隔符
分隔符主要用于分隔其它的词法符号
主要包括: 空格符,制表符,执行符号,注释,通过对分隔符的恰当运用,使得代码的外观清晰易读, 易于分析语法错误
3.4 运算符
运算符是表示运算的词法符号,c语言有着丰富的运算
按照功能分: 算术运算符,逻辑运算符,关系运算符,位运算符,赋值运算符,自增自减运算符,地址运算符,逗号运算符 sizeof运算符
3.5 标点符号
逗号,分号,冒号,花括号,圆括号,标点符号的作用和分隔符类似,但是用法有明确的语法规定,有些标点符号 出现在表达式中时,当作运算符使用。
四 数据类型
数据类型 1.基本类型: 1>:整形:short,int,long,long long 有符号:signed 无符号:unsigned 2>:字符型:char 3>: 实型:float double 4>: 枚举类型:enum 2.构造类型 1> 结构体 struct 2> 共用体 union 3.指针类型 4.空类型 void 逻辑类型 只有两个量true和lfalse ,表示逻辑真和逻辑假
4.1 逻辑类型bool类型
#include <stdio.h> #include <stdbool.h> int main(int argc, const char *argv[]) { //定义一个bool类型的变量并赋值为10 //注意:c语言默认不支持bool类型,需要使用_Bool或者添加头文件stdbool.h //bool类型只有两个值0和1,非0即为真,所有所有非0的值都等于1 //bool类型主要用判断语句,判断条件是否成立 bool b = 10; //%d:有符号整型输出 printf("b = %d\n",b); bool c = 0; printf("c = %d\n",c); bool d = 0.0000000001; //%d:有符号整型输出 printf("d = %d\n",d); _Bool e = 23456879; printf("e = %d\n",e); return 0; }
4.2 整数类型
4.2.1 char
char类型占一个字节
有符号:char或者 signed char
取值范围:-2^7 - 2^7-1 ---> -128 - 127
无符号: unsigned char
取值范围:0 - 2^8-1 --> 0 - 255
4.2.2 short
short类型占两个字节
有符号:short或者 signed short
取值范围:-2^16/2 - 2^15-1 ---> -32768 - 32767
无符号: unsigned short
取值范围:0 - 2^16-1 --> 0 - 65535
4.2.3 int
int类型占四个字节
有符号:int或者 signed int
取值范围:-2^32/2 - 2^31-1 ---> -2,147,483,648 - 2,147,483,647
无符号: unsigned int
取值范围:0 - 2^32-1 --> 0 - 4,294,967,295
4.2.4 long
long类型在32位操作系统占四个字节,在64位操作系统占8个字节
有符号:long或者 signed long
取值范围:-2^64/2 - 2^63-1
无符号: unsigned long
取值范围:0 - 2^64-1
#include <stdio.h> int main(int argc, const char *argv[]) { //定义一个char类型变量并赋值 char a = 100; printf("a = %d %c\n",a,a); short b = 20000; printf("b = %d\n",b); int c = 34253452; printf("c = %d\n",c); //如果是long类型,要用%ld输出 long d = 12345678998765; printf("d = %ld\n",d); return 0; }
4.3 浮点类型
浮点类型也叫做实型,就是带有小数点的数据
float 单精度 占4个字节
double 双精度 占8个字节
#include <stdio.h> int main(int argc, const char *argv[]) { //float类型输出变量要使用%f //float类型默认保留小数点后6位,并且会四舍五入 float a = 3.141592653; printf("a = %f\n",a); float b = 5.6; printf("b = %f\n",b); //如果一个浮点数数据非常大,末尾小数可能会丢失精度 float c = 234567864.999; printf("c = %f\n",c); double d = 24.23456122; printf("d = %lf\n",d); return 0; }
4.4 数据在计算机中的存储
我们人为设置的数据称为原码
存储在计算机中的数据称为补码
为了实现原码和补码的转换,加入了反码
存储数据的顺序:原码--->反码---->补码
取出数据的顺序:补码--->反码---->原码
如果一个数是正数,原码 反码 补码都一样
如果一个数是负数,最高位为符号位,符号位为1表示负数
负数的反码等于原码取反(将这个数转化为二进制之后,原本1变成0,0变成1,),但是符号位不便,补码等于反码加1.
技巧:存储时看数据,取出时看类型
unsigned char = 100; 存储时: 原码:0110 0100 反码:0110 0100 补码:0110 0100 取出时: 补码:0110 0100 反码:0110 0100 原码:0110 0100 = 100 signed char = -10; 存储时: 原码:1000 1010 反码:1111 0101 补码:1111 0110 取出时: 补码:1111 0110 反码:1111 0101 原码:1000 1010 signed char = 129; 存储时: 原码:1000 0001 反码:1000 0001 补码:1000 0001 取出时: 补码:1000 0001 反码:1000 0000 原码:1111 1111 = -127
为什么 -128-1 = 127?
4.4.1 浮点类型数据的存储
浮点类型是一个拼凑出来的近似值,并不一定是实际值,原因是小数位也要转化成二进制的小数位。
五 常量
常量是指在程序在运行期间其数值不会发生变化的数据
5.1 整数常量
十进制: %d
八进制:%#o
十六进制:%#x
#include <stdio.h> int main(int argc, const char *argv[]) { int num = 1000; printf("num = %d\n",num); printf("num = %#o\n",num); printf("num = %#x\n",num); int a = 0756; int b = 0xab8f; int c = 0b100011110; printf("a = %d, %#o %#x\n",a,a,a); printf("b = %d, %#o %#x\n",b,b,b); printf("c = %d, %#o %#x\n",c,c,c); return 0; }
5.2 浮点型常量和指数常量
float:%f
double: %lf
指数常量就类似于科学计数法:
678900---->6.789*10^5---->6.789e+5 //使用%e输出指数常量
指数常量的格式:<+/->m.ne<+/->i; 例如:-3.14*10^-7 ---->-3.14e-7
#include <stdio.h> int main(int argc, const char *argv[]) { float a = 345568.123; printf("a = %f\n",a); printf("a = %e\n",a); float b = -1.78e-5; printf("b = %f,%e\n",b,b); return 0; }
5.3 字符常量
字符:将一个单一的非数值型数据用单引号引起来,就将其称之为一个字符。
例如:'a' 'y' '9'
#include <stdio.h>
int main(int argc, const char *argv[])
{
char a = 'w';
printf("a = %d %c\n",a,a);
char b = 97;
printf("b = %d %c\n",b,b);
char c = 'w';
printf("c = %c\n",c);
c = c-32;
printf("c = %c\n",c);
return 0;
}
执行结果:
5.4 字符串常量
将一个或者多个字符通过双引号引起爱,将其称之为一个字符串,每一个字符串的结尾都会自动加一个'\0'
例如:“Helloworld” "a" "abc" "1234";
注意:
a 是一个变量 'a':是一个字符常量,占一个字节 "a":是一个字符串常量,占两个字节
#include <stdio.h>
int main(int argc, const char *argv[])
{
//定义一个字符数组保存字符串
char str[32] = "hello world";
//使用%s来输出一个字符串
printf("str = %s\n",str);
//遇到\0表示字符串结束
char str1[32] = "hello wo\0rld";
printf("str1 = %s\n",str1);
return 0;
}
5.5 标识常量 ----宏定义
将一个常量或者常量表达式标识成另一个标识符,使用这个标识符就相当于使用这个常量或者常量表达式,也将其称之为宏定义,这个标识符一般使用大写字母表示,并且要满足标识符的命名规则。
格式:
#define 标识符 常量或者常量表达式
例如:
#define N 32
#include <stdio.h>
#define M 128
#define N 32
#define SUM M+N
#define SUM1 (M+N)
#define SUB(a,b) (a-b)
int main(int argc, const char *argv[])
{
int i = M + 5;
printf("i = %d\n",i);
int a = N +M;
printf("a = %d\n",a);
int b = SUM + 100;
printf("b = %d\n",b);
//128 + 32 * 10 int c = SUM*10;
printf("c = %d\n",c);
//(128 + 32) *10
int d = SUM1 *10;
printf("d = %d\n",d);
int e = SUB(10,5) + 100;
printf("e = %d\n",e);
return 0;
}
练习:
一个水分子的质量约为3.0*10^-23g,1L水大约950g,编写一个程序,要求输入水的升数,然后显示这么多升水中包含多少个水分子。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int num;
scanf("%d",&num);
printf("num = %d\n",num);
return 0;
}
#include <stdio.h>
#define WATERWEIGHT (3.0e-23)i
#define WATERL 950
int main(int argc, const char *argv[])
{
int L;
printf("请输入水的升数:\n");
scanf("%d",&L);
double num = WATERL /WATERWEIGHT * L;
printf("%dL水中有%e个水分子\n",L,num);
return 0;
}
六 变量
6.1 概念
变量,就是我们自己定义的变量名,变量就是可以改变其值的量,变量就是一个标识符,所以需要满足标识符的命令规则。
在程序的运过程中,变量占据一定的内存空间,其大小由变量数据类型来决定的
例如:
int a;//变量a在内存中占四个字节
char b;//在内存中就分配一个字节
#include <stdio.h>
int main(int argc, const char *argv[])
{
//定义一个变量
int i;
//变量的初始化,在定义变量的同时赋值
int a = 100;
int b;
//变量赋值,这个变量已经定义好之后再赋值
b = 200;
//注意:在同一个{}内,同一个变量名不能定义两次
//long b = 88;
a = 888;
b = 999;
//变量和变量之间可以赋值
//等号左边叫做左值,等号右边叫做右值,是将右值赋值给左值
//右值不会发生改变
i = a;
return 0;
}
6.2变量定义格式
格式: 存储类型 数据类型 变量; 存储类型:有四种 auto:默认不写就是这个类型 register static extern 数据类型:就是我们之前学习的char,int等 变量名:就是起名字,是一个标识符
6.3 类型转换
原本的变量在使用的额过程中需要改变他的类型,转换之后这个变量的类型以及存储空间都会发生改变。
类型转换的方法:
隐式类型转换:是操作系统或者编译器自动进行转换的
显示类型转换:又称之为强制类型转换,是我们人为直接转换的
显示的数据类型转换一般形式为:
(数据类型名称)<表达式>
#include <stdio.h>
int main(int argc, const char *argv[])
{
//隐式类型转换:当float类型赋值给int类型的时候,就会将a临时转换成int再赋值给b
//隐式类型转换默认一从低精度往高精度转
float a = 3.14;
int b = a;
printf("b = %d\n",b);
int i= -20;
unsigned int j = 6;
if(i + j > 0) { printf("i + j > 0,%u\n",i+j);
}
else
{
printf("i + j <= 0");
}
int m = 10,n = 4;
//printf("%d\n",m/n);
printf("%f\n",(float)m/n);
printf("%f\n",(float)m/(float)n);
return 0;
}
强制类型转换注意事项:
强致类型转换后面的表达式如果存在复杂运算,一定要用小括号括起来。
强制类型转换是一种不安全的转换,一般都是将高级类型转成低级类型,要丢失数据的精度
强制类型转换并不改变表达式中变量的数据类型和其值。
七 运算符
7.1 算术运算符
双目运算符:运算符的两边各有一个变量
+ - * / %
单目运算符:运算符边上只有一个变量
++ --
%:取余,只能用在整数,浮点数据不能取余
++:自增,每次自增1
--:自减,每次自减1
练习2:输入一个三位数,求个位,十位,百位的和
789---> 7 + 8 + 9
789 /100 = 7
789 %10 = 9
789 %100 /10 = 8
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int num; printf("请输入一个三位数:\n");
scanf("%d",&num);
if(num > 999 || num < 100) { exit(0);
}
int ge,shi,bai,sum;
ge = num % 10;
shi = num % 100 /10;
bai = num / 100;
sum = ge + shi + bai;
printf("sum = %d\n",sum);
return 0;
}
练习3:输入两个数,实现这两个数的交换
int m,n;
scanf("%d %d",&m,&n);
m = 100,n = 50;
.....
m = 50,n = 100;
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("请输入两个数:\n");
int m,n;
scanf("%d %d",&m,&n);
printf("交换前:m = %d,n = %d\n",m,n);
#if 1 int tmp;
tmp = m;
m = n;
n = tmp;
#else m = m+n;
n = m-n; m = m-n;
#endif printf("交换后:m = %d,n = %d\n",m,n);
return 0;
}
7.2 关系运算符
> < >= <= == !=
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 10,b = 20,c;
//使用关系运算符的表达式的结果是一个bool类型 //表达式为真,则结果为1,表达式为假,结果为0
c = a > b;
printf("c =%d\n",c);
c = a < b;
printf("c =%d\n",c);
if(a > b) { printf("hello world!\n");
}
else
{
printf("hello nanjing\n");
}
return 0;
}
7.3 逻辑运算符
逻辑运算符主要是用于连接多个有关系运算符连接的表达式,判断整体表达式为真为假
!:逻辑反,原本表达式为真变为假,为假则变为真
!(A > B) ====> A
&&:逻辑与,两个表达式都为真才为真,只要有一个为假则整体为假
||:逻辑或,有一个为真则整体为真,除非都为假才为假
判断一个变量a的值是否在10-20的范围内:
数学:10 c语言:a >= 10 && a
判断一个变量a的值是否不在10到20的范围内:
数学:a < 10 或 a > 20
c语言:a < 10 || a > 20
#include <stdio.h>
int f1()
{
printf("this is f1\n");
return 0;
}
int f2()
{
printf("this is f2\n");
return 1;
}
int main(int argc, const char *argv[])
{
/* int a = 100,b;
//b = 10 <=a <=20;
b = a >=10 && a <= 20;
printf("b = %d\n",b); */
int a = 1,b = 0;
if(f1() && f2())
//短路原则:如果条件1不成立,则不会判断条件2
{
printf("hello world!\n");
}
if(a && b) //两个表达式都要成立
{
printf("hello tianjing!\n");
}
if(a ||b) //逻辑或,有一个表达式成立就行
{
printf("a || b成立!\n");
}
return 0;
}
7.4 位运算
但凡涉及到位操作,一定先将这个数转化为二进制数,然后再操作
~ 位逻辑反
& 位逻辑与,同为1则为1,否则为假, 1&1 = 1 ,1&0 = 0 ,0 &0 = 0
| 位逻辑或,只要有一个为1则为1
^ 位逻辑异或,相同为0,不同为1 1^0 = 1 ,0^0 = 0 ,1^1 = 0
>> 右移
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned char m = 0xa7,n = 0x3b;
unsigned char k; //逻辑反 k = ~m; //m:
1010 0111 //~m:0101 1000 = 0x58 printf("k = %#x\n",k);
k = m & n;
//m: 1010 0111
//n: 0011 1011
//m&n: 0010 0011 = 0x23
printf("k = %#x\n",k);
//左移 k = m << 3;
//m:1010 0111 //m:0011 1000->0x38
printf("k = %#x\n",k);
//右移 k = n >> 3;
//n: 0011 1011
//n >>3:0000 0111-->0x07
printf("k = %#x\n",k);
return 0;
}
7.5 赋值运算符和赋值符合运算符
赋值运算符:=
左值 = 右值
注意:左值必须是变量,右值可以是变量也可以是常量
注意事项:
=:表示赋值
==:表示判断是否相等
赋值复合运算符:
a = a+b------>a+=b;
a^=b
a>>=b--->a = a >> b
7.6 条件运算符---三目运算符
语法格式:
表达式1?表达式2:表达式3
运行顺序:
先执行表达式1,如果表达式1为真则执行表达式2,如果表达式1为假,则执行表达式3
条件运算符其实就是一个简单的if....else语句
if(表达式1)
{
表达式2
}
else
{
表达式3
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 100,b = 20,c;
c = a > b ? ++a : b++;
printf("a = %d,b = %d,c = %d\n",a,b,c);
return 0;
}
2.7 逗号运算符
语法格式:
a = (表达式1,表达式2,表达式3,表达式4);
执行顺序:
括号里面的表达式从左往右依次执行,最终整个表达式的结果是最后一个表达式的结果
注意:
逗号运算符必须使用括号
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 100,b = 40,c;
//c = (++a,++b,a = a+b,a++);
printf("a = %d,b = %d,c = %d\n",a,b,c);
c = a+++b; //c = a+++(++b);
printf("a = %d,b = %d,c = %d\n",a,b,c);
return 0;
}
7.8 sizeof运算符
sizeof是一个关键字,也是一个运算符,主要用于获取一个数据类型或者变量所占内存的大小
语法格式:
n = sizeof(数据类型或者变量名)
n:用于保存这个数据类型或者变量名所在内存的字节数
例如:n = sizeof(int) --->n = 4;
#include <stdio.h>
int main(int argc, const char *argv[])
{
_Bool a; char b; short c;
int d; long e;
float f; double g;
long long h;
printf("sizeof(_Bool) = %ld %ld\n",sizeof(_Bool),sizeof(a));
printf("sizeof(char) = %ld %ld\n",sizeof(char),sizeof(b));
printf("sizeof(short) = %ld %ld\n",sizeof(short),sizeof(c));
printf("sizeof(int) = %ld %ld\n",sizeof(int),sizeof(d));
printf("sizeof(long) = %ld %ld\n",sizeof(long),sizeof(e));
printf("sizeof(float) = %ld %ld\n",sizeof(float),sizeof(f));
printf("sizeof(double) = %ld %ld\n",sizeof(double),sizeof(g));
printf("sizeof(long long) = %ld %ld\n",sizeof(long long),sizeof(h));
return 0;
}
2.9 运算符的优先级
当不确定表达式中多个运算符的优先级时,使用()来解决 。
后缀++或--的优先级大于前缀++或--的。
*p++后缀++优先级高于*,所以先执行++,再执行* ;*++p前缀++和*优先级一样,但是是从右向左结合,所以先执行++,再执行* 。
a = b = c = d; =的结合规律是从右向左,所以是从右向左依次赋值 。
a = b == c; 先判断b和c是否相等,然后将结果赋值给a 。
算术运算符(* / + -)的优先级大于位运算符,位运算符(& | ^)的优先级大于逻辑运算符(&& ||) 。
a & b + c,先算b+c的结果,然后再和a相与。