c语言中程序总是从main函数开始执行,且总是默认从main函数的return语句或结尾处结束运行。
C++中全局main函数的书写格式与C语言完全相同,功能也完全相同,且同一C++程序同样只能有一个全局main函数。
#include
int main() //int main 是主函数
{
printf("Hello World\n");
return 0; //主函数返回值
}
add前面的int表示函数返回值是int类型,c语言里 函数的参数可以定义类型,与ts类似 传入的实参也必须一致 否则报错
所有的C语言代码都有一个起始入口,而这个入口就是主函数main。进入了主函数以后,才能经由主函数来调用其他函数。
这也意味着,每个C语言代码,只能有且只有一个main函数。
#include
int add(int a, int b)
{
return a + b;
}
int main()
{
int result;
result = add(2, 3);
printf("%d", result);
return 0;
}
当程序运行时,首先会进入主函数main。接着调用我们刚刚编写的add函数了。我们传了2个值分别是整数2和3给add函数。
编译器会从代码开始,按照从上往下的顺序阅读代码。
因此 函数在调用之前需要被定义 否则会报错
编译器首先看到了一个函数的定义,描述了一个叫add的函数。接着,在main中需要使用add,由于编译器已经知道了add的定义,因此编译器可以正常编译通过。
与js不同 变量必须先声明后赋值
变量按作用域分为局部变量 && 全局变量
1. 局部变量的作用域是变量所在的局部范围。(就是大括号里边的变量只能在大括号里用)
2. 全局变量的作用域是整个工程。(就是大括号外边的变量在哪都能用)
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。(大括号大括号!)
2. 全局变量的生命周期是:整个程序的生命周期。 (在哪都行!)
概括来说作用域就是变量在哪能用,生命周期就是它啥时候产生,啥时候消失。
c语言中的字面常量?
那么,像2,3,这种数值,需不需要声明呢?
不需要,他们是常量,无法被更改。并且一旦被写出来,就已经知道它们是整型的常量了。
同样的,字符串字面常量也不需要被声明,例如:"Hello World\n"。被双引号包裹的,我们认为它是一个字符串,以区别于数值。
变量我们可以通过赋值来更改,常量不能更改,所以你不能对它进行赋值。
2 = 3; // 错误
"Hello" = "World"; // 错误
printf函数
...
#include
char//字符数据类型//就是不是数字的字符
short//短整型//就是数字小(绝对值)的整数,很少用
int //整型//就是整数
long//长整型//就是数字(绝对值)大的整数
long long//更长的整型//很少用
float//单精度浮点数//就是小数
double//双精度浮点数//小数位数多的小数
构造类型
数组类型:
数组的定义:一组相同类型元素的集合
与js不同 js数组元素用[ ]括起来表示 c语言中用 int arr[3]={ 1,2,3} 来声明一个数组
结构体类型 struct
枚举类型 enum
联合类型 union
4.指针类型
int *pi;
char *pc;
float* pf;
void* pv;
5.空类型
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
1字节=8比特位 (Byte字节)
比特位即bit,是计算机最小的存储单位,信息量单位。以0或1来表示比特位的值。愈多的比特位数可以表现愈复杂的图像信息。
一个int整形数据 分配四个字节存储,也就是8个位,32个字节
000000000000000000000000
000000000000000000000000
有符号数是针对二进制来讲的。用最高位作为符号位,“0”代表“+”,“1”代表“-” ;其余数位用作数值位,代表数值。
有符号数的表示:计算机中的数据用二进制表示,数的符号也只能用0/1表示。一般用最高有效位(MSB)最左边的位来表示数的符号,正数用0表示,负数用1表示。
计算机中的有符号数有三种表示方法,即原码、反码和补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位 三种表示方法各不相同。
原码
直接将二进制按照正负数的形式翻译成二进制就可以。
反码
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码
反码+1就得到补码。
算术操作符:
+ - * / %
求模运算符(%)
对于求模运算符来说,其运算结果是,两个数做除法,取他们的余数,特别要注意:%操作符的操作数,必须是整数。
移位操作符
<< >>
(想理解移位操作符具体怎么移的,需要知道 二进制转换x进制的规则,需要知道计算机中原码,反码,补码的概念
)
在移位操作中,移的位都是二进制位,所以我们如果拿到一个非二进制的数,我们要先把他转换成二进制数。
左移的详细过程:先把10转化成32位二进制序列,移位规则就是:左移一位,左边丢弃,右边补一个0,我们可以用一个代码来验证结果。
左移的确是将左边的位丢弃,右边补0,但是,对于被操作的a本身来说,它的值并不会被改变。
右移详细过程:
右移运算可以分为两类,逻辑右移和算术右移
逻辑右移 左边用0补位 右边丢弃
算术右移,左边用原来符号补位 右边丢弃
位操作符
& | ^
按位与 |
c = a & b;//按(2进制位)位与
//规则:对应位都是1,按位与为1,只要有一个不是1,那么按位与为0
//a:00000000000000000000000000000011
//b:00000000000000000000000000000101
//a&b:00000000000000000000000000000001
按位或 &
//规则:对应位只要有一个1,那么就按位或为1
//a:00000000000000000000000000000011
//b:00000000000000000000000000000101
//a|b:00000000000000000000000000000111
按位异或 ^
//规则:对应位,相同为0,相异为1
//a:00000000000000000000000000000011
//b:00000000000000000000000000000101
//a|b:00000000000000000000000000000110
赋值操作符
= += -= *= /= %= >>= <<= &= |= ^=
"="用来赋值
int a =0;//把0赋值给a
其余的为复合赋值
例如:
x = x +1;x +=1;
上面这两种写法是完全等价的,复合赋值就是为了简洁,每一个符合赋值的运算符道理都和上面的一样。
单目操作符
! - + & sizeof ~ -- ++ * (类型)
1、逻辑反操作(!)
常用于判断中
int i = 0;
if(!i) //!0即为真
{
printf("nihao");
}
这行代码的意思是,如果i的逻辑反为真值,就执行if语句中的语句。
2、负值(-)
#include
int main()
{
int a = 3;
a = -a;
printf("%d", a);
return 0;
}
3、正值(+)
#include
int main()
{
int a = 3;
a = +a;//正数通常省略+
printf("%d", a);
return 0;
}
4、取地址(&)
用来取地址
#include
int main()
{
int a = 10;
printf("%p\n", &a);//用来取出a在内存中的地址,打印地址用%p
return 0;
}
5、sizeof(求操作数的类型长度,以字节为单位)
int main()
{
int a = 3;
printf("%d", sizeof(a));//计算int类型的长度
return 0;
}
6、按位取反(~)
#include
int main()
{
int a = -1;
a = ~a;
//10000000000000000000000000000001 --原码
//11111111111111111111111111111110 --反码
//11111111111111111111111111111111--补码
//按位取反
//11111111111111111111111111111111--内存中的a
//00000000000000000000000000000000--取反之后
printf("%d", a);
return 0;
}
7、自减(--)
#include
int main()
{
int a = 3;
int b = 0;
int c = 0;
b = a--;//后置--,先使用,再--
c = --a;//前置--,先--,后使用
printf("%d\n", b);//3
printf("%d\n", c);//1
return 0;
}
8、自增(++)
#include
int main()
{
int a = 3;
int b = 0;
int c = 0;
b = a++;//后置++,先使用,再++
c = ++a;//前置++,先++,后使用
printf("%d\n", b);//3
printf("%d\n", c);//5
return 0;
}
9、间接访问(*)
#include
int main()
{
int a = 10;
int* pa = &a;//创建一个指针变量
*pa = 20;//*--解引用操作符-间接访问操作符
printf("%d\n", a);//20
return 0;
}
10、强制类型转换((类型))
#include
int main()
{
int a = (int)3.14;//将double类型强制转换为整型
printf("%d\n", a);
return 0;
}
关系操作符
> 大于
>= 大于或等于
< 小于
<= 小于或等于
!= 不等于
== 等于
这些关系操作符与数学中的符号意思一样,通常用来进行判断
特别注意“==”和“=”不一样
逻辑操作符
&& ||
1、逻辑与(&&)
用来表示并且
只有&&两边的表达式均为真,才表示真
例如:1&&3 为真
1&&0 为假
2、逻辑或(||)
只要||一边的表达式为真,整个表达式就为真
例如:1||0 为真
八、条件操作符
表达式1?表达式2:表达式3
条件操作符又称为三目操作符
可以解读为,如果表达式1成立,则执行表达式2的值,否则执行表达式3的值
#include
int main()
{
int a = 3;
int b = 5;
int max = (a > b ? a : b);//用来找到两数的较大值
printf("%d\n", max);
return 0;
}
逗号表达式
表达式1,表达式2,表达式3,......表达式n
逗号表达式,顾名思义就是用逗号隔开的表达式
表达式的结果:从左向右依次执行,整个表达式的值是最后一个表达式的结果
#include
int main()
{
int a = 3;
int b = 5;
int c = (a + b, b + 1, a++);//最后一个表达式的值
printf("%d\n", c);//3
return 0;
}
下标引用、函数调用和结构成员
1、下标引用([])
用于数组,操作数:一个是数组名,另一个是下标
#include
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
printf("%d", arr[4]);//[下标]用来访问数组中第5个元素
return 0;
}
2、函数调用
#include
void test()
{
printf("nihao");
}
int main()
{
test();//()作为函数调用的操作符
return 0;
}
3、访问结构成员
. 结构体.成员名
#include
struct Book
{
char name[20];
char id[10];
int price;
};
int main()
{
struct Book b = { "nihao","KN16798",10 };
printf("%s\n", b.name);
printf("%s\n", b.id);
printf("%d\n", b.price);
return 0;
}
-> 结构体->成员名
#include
struct Book
{
char name[20];
char id[10];
int price;
};
int main()
{
struct Book b = { "nihao","KN16798",10 };
struct Book* pb = &b;
printf("%s\n", pb->name);
printf("%s\n", pb->id);
printf("%d\n", pb->price);
return 0;
}
1. if语句
2. if...else语句
3.if...else if...else 语句
4. switch 语句
switch(2){
case 0 :{
}
case 1:{
}break;
default:{}
}
for循环
while循环
do...while语句
int i = 0;
do
{
i++;
}while(...)
如果while括号中结果为假,do中的操作都是一定先执行的,也就是说do...while循环至少执行一次。
由于通过地址能找到所需的变量单元,可以说,地址指向变量单元,打个比方,一个房间的门口挂了一个房间号2008,这个2008就是房间的地址,或者说,2008"指向"该房间.因此,将地址形象化地称为“指针”。意思是通过它能找到以它为地址的内存单元!
定义指针变量
1.1 定义指针变量
与定义普通变量非常类似,不过要在变量名前面加星号*,格式为:
datatype *name;或者
datatype *name = value;
*表示这是一个指针变量,datatype表示该指针变量所指向的数据的类型 。
例如:
int a=10
int *p=&a; &是取地址符号 a变量是int类型 所以占用4个字节byte空间 指针p指向存放a的第一个字节的地址存放在p指针中
例 通过指针变量访问整型变量
int main() {
int a = 100, b = 10;//定义整型变量a,b并初始化
int* p1, * p2; //定义指向整型数据的指针变量p1,p2;
p1 = &a; //把变量a的地址赋给指针变量p1
p2 = &b; //把变量a的地址赋给指针变量p2
printf("a=%d,b=%d\n", a, b);//输出变量a和b的值
printf("*p1=%d,*p2=%d\n", *p1, *p2);
}
在开头处定义了两个指针变量p1和p2。但此时他们并未指向任何一个变量,只是提供两个指针变量,规定他们可以指向整型变量,至于指向哪一个整型变量,要在程序中指定.。程序第五第六行的作用就是使p1指向a,使p2指向b,此时p1的值为&a(即a的地址),p2的值为&b(即为b的地址)
*注意:定义指针变量时,左侧应有类型名,否则就不是定义指针变量.
所谓数组元素的指针就是数组元素的地址
可以用一个指针变量指向一个数组元素。例如
int arr[10]={1,3,5,7,9,11,13,15,17,19}; //定义a为包含10个整型的数组
int *p; //定义p为指向整型变量的指针变量
p=&a[0]; //把a[0]元素的地址赋给指针变量p
根据代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样
实际上&arr表示的是数组的地址而不是数组首元素的地址。
数组的地址+1 跳过整个数组的大小,所以&arr+1相对于&arr的差值是40.