整形提升是啥???
表达式中参与运算且凡是小于int类型(如:char,short)的都会进行整形提升,之后才会放入到cpu中进行计算
//凡是参与运算且小于int类型的都会向int类型转换,再执行运算
二维数组传参???
关于宏还是不太理解???
*****注意:在c语言中
二进制:想用二进制表示某个数,前面需要加上“0b”(貌似并不区分大小写)
八进制:想用八进制表示某个数,前面需要加上“0”
十六进制:想用十六进制表示某个数,前面需要加上“0x”
详解c语言字符串:
字符串:以“\0”为结尾的一维字符数组,其中\0代表着字符串的结束
\0(Null):结束符,它是转义字符,意思是“Null”空字符
整数在内存的存储形式:整数存放在内存中的皆为“补码”
有符号位:分为“正数”和“负数”
正数:原码-反码-补码(相同)
负数:原码-反码-补码(都不相同)
无符号位:
原码-反码-补码(相同)
关于数据在内存中的进制位是倒着存储:(大小端描述的是“字节”的顺序)
大端(大端字节序存储模式):数据的底位保存在内存的高地址,而数据的高位,保存在内存的低地址(正序)
小端(小端字节序存储模式):数据的底位保存在内存的底地址中,而数据的高位,保存在内存的高地址中(倒序)
注意:内存的存储是“左面是底地址,右面是高地址”
低地址---------------------------------->高地址
关于RAM(运存):运行内存,用于正在运行中的程序的临时资料存储媒介,断电时数据丢失
主要存储短时间内使用的程序
又称为“随机存储器”,就是电脑的内存条。用于存放动态数据
关于ROM(只读存储器):也就是硬盘,对于手机来说就是“内存存储”
在c语言中浮点型的存储方式:(看不懂了。。。。)
**注意:在c语言中整型的存储方式和浮点型的存储方式差异过大,取值的方式也不尽相同
所有的浮点型都可以换算成一个表达式:先将十进制转换成二进制
(-1)^ s * M * 2^E //科学计数法???
// -1是固定的,“ * ”表示的是乘号
// “ s ”表示的是符号位
// “M”表示的是有效数字(有效数字只有一个整数,其余的皆为小数,如果不符合条件,则会小数点向左移动,直到符合条件,移动的位数用 “2^E”来表示)
// 2 表示的是当前为二进制
// E 表示2的指数位,也就代表着小数点向左移动几位
E换算成二进制全为0,在存储的时候是一个固定值,为“2^1-127”
E常规的存储方式,在存储的时候当前值加上127,然后换算成二进制,进行存储
c语言文件以 .c 为后缀 (注意:c语言是面向过程的语言,没有对象的概念,貌似也没有类的概念)
.h 是头文件 head (注意:所有编程语言的代码,都是由上而下执行)
//:单行注释 (*****注意:C语言语法规定,变量要定义在当前代码块的最前面)
使用输入输出库是需要导入 : #include(包含) <stdio.h> (类似于其他高级语言中的导库)
#include:将头文件全都拷贝进来
扩展:(TIOBE语言排行榜)
关于内存如何产生地址的:
电脑中的32位和64位:(内存空间的划分)32位代表的是32根地址线/数据线,每根线又有正电和负电之分,所以通过这些地址线得到32个二进制位,经过变化得到2^32次方个地址位 (这就是内存当中每块空间的二进制序列号,也就是地址位)
一个内存单元(一个地址位所代表的的一块空间):用一个字节合适
注意:取地址操作符(&),可以得到该空间的地址位(二进制序列号)
关于设置电脑关机:在控制台输入“shutdown -s -t 60”,电脑会在“1分钟”后关机
shutdown -s :设置关机
-t :设置定时关机
60:设置定时关机时间,单位为秒数
shutdown -a:取消关机
MSDN:c语言文档网站
cppreference.com:c和c++的官网
注意事项:
**注意:在c语言中整型的存储方式和浮点型的存储方式差异过大,取值的方式也不尽相同
c语言中里面有“实参”和“形参”的概念
注意:数值和字符之间是可以比较的,其中是按照ASCII码进行比较
注意:转义字符代表的是一个字符
注意:c语言中函数在定义时并没有指定形参,调用函数的时候却可以传入实参(非常模棱两可)
注意:凡事以#开头的代表这是一个预处理命令
先去写函数怎么用,再去写函数怎么实现
stack overflow(栈溢出):加上.com,就是一个程序员知乎网站
在c语言中“真”与“假”:
真:用非0表示
假:用0表示
EOF:是end of file(文件结束标志,值是-1),快捷键ctrl+z
输入缓冲区:输入函数所取的值都是在输入缓冲区中取得的,而输入缓冲区内的数据都是键盘上所输入的操作值
关键字:
extern:引入外部符号(引入另一个.c文件的全局变量,或者函数)
示例:
extern int g;//int g 是另一个文件的全局变量
extern int Add(数据类型 变量);//main函数外,引入int Add(数据类型 变量)另一个文件的函数
auto关键字:局部变量的声明,不过一般都会省略掉
register:建议把某个变量定义成寄存器变量
寄存器:cup去取数据的第一个点 //取数据的四个步骤
高速缓存
内存
硬盘
signed:signed==signed int ==int (定义的变量是有符号的,符号位)
只不过平时将signed省略掉了
unsigned:无符号的,没有符号位(貌似是绝对正数)
struct:结构体关键字
typedef:类型定义(类型重定义),给数据类型创建一个别名
示例:
typedef float f;给float创建一个叫“f”的别名
对于函数指针类型定义别名时,定义的格式与上不同
示例:
//下面的函数类型是:void(*)(int)
typedef void (* 别名)(int);
static:静态的,修饰局部变量,局部变量的生命周期变长
修饰全局变量,改变了全局变量的作用域,静态的全局变量只能在源文件内部使用,无法在使用extren引入到其他文件中使用
修饰函数,改变了函数的作用域(改变了函数的链接属性)
将函数的外部链接属性改成了内部链接属性,无法在去从另一个文件引用extern
void:空的(表示类型的缺失)
define:标识符常量关键字,宏的定义关键字 (不是关键字而是一种指令???)
示例: #define 变量名 值
宏(与函数不同):
#define MAX(X,Y)(X>Y?X:Y)//使用宏的方式与函数类似
#include <stdio.h>
//main函数调用,返回一个整型(有void,但main不建议使用)
int main(){ //主程序入口(代码从这开始执行) ,main函数有且仅有一个,int 整型
printf(“hehe\n”);//输出打印(\n应该是换行)
return 0; 返回值
}
<limits.h>:该头文件拥有整数型的取值范围
<float.h>:该头文件拥有浮点型的取值范围
时间戳:
当前计算机的时间-计算机的起始时间(1970.1.1. 00:00:00)=(x,x,x,x)秒
关于进制之间的转换:
例: 6 1 //本身为16进制
6*16^1 1*16^0
函数方法:
time(time_t *timer):获取当前系统时间(头文件 <time.h>)
参数time_t * 是指针变量,参数可以为NULL(空指针)
srand(int类型数值):为rand函数设置随机数起始点(头文件与rand函数相同)
参数类型是 unsigned int (这是无符号正数)
参数推荐使用“时间戳”,因为只有srand函数参数发生变化,rand函数的返回值才会不同
注意:不要频繁调用,设置一次就好
rand():生成一个随机数,返回值是int类型(头文件 <stdlib.h>)
strcmp(字符串1,字符串2):用来比较两个字符串是否相等(==双等于不能比较两个字符串)
注意:返回值是“0”的话,代表两个字符串相等
scanf(“%d%d”,&变量,&变量):输入函数 (&取地址符号)
注意:scanf只会读走空格前面的数据
接收 整型(%d) 数据,获取两个变量的内存地址,将接收的数据赋值给两个变量(&取地址符,获取变量的内存地址)
getchar():返回值类型int , 从控制台获取输入字符(输入函数)
putchar(int ):控制台输出字符(将数字在控制台以字符的形式输出)
strcpy(目的地,要操作的对象):(全称 string copy)拷贝的意思,需要使用 “string.h”头文件,字符串拷贝
会覆盖目的地里面的内容,且会连同\0(文件结束标志)一起拷贝进去
sizeof(“数据类型”| 变量):该函数 计算变量或数据类型的所占空间(内存)大小,支持参数为数组,计算单位是“字节”
注意:sizeof()内部的表达式不会参与运算
注意:sizeof是个“操作符”,括号是可以省略掉的,但是查询数据类型时不能省略
返回值为无符号数,无符号数和其他类型进行比较时会转换成无符号数,在进行比较
求数组元素个数:
数组元素个数=sizeof(arr)/sizeof(arr[0])
数组总容量 / (除) 单个元素容量
printf():print 打印 , f 其实是 function(函数),这一整句话是 打印函数 int类型返回值,返回的是打印字符的个数
示例:printf(“%c”,字符变量) // %c,打印字符格式的数据
%c:打印字符格式的数据
%d:打印整型十进制的有符号数字(%2d,打印两位,不足两位用空格补齐,右对齐。%-2d,左对齐)
%o:打印八进制整数的格式化形式
%x:打印十六进制
%u:打印十进制无符号数字
%ld:比%d的输出字节要长,可以理解为long整型十进制的有符号数字
%f:打印浮点数据
%p:以地址的形式打印
%s:字符串打印
%lu:32 位无符号整数
%E:以指数形式输出单、双精度实数
strlen():string length - 计算字符串长度,计算时并不会将“\0”文件结束标志算上(该函数头文件,<string.h>)
注意:转义字符代表一个字符
*****求的是\0之前的字符个数,直到碰到\0,才会有返回值
参数如果是数组时,且数组末尾元素不是\0,返回值为随机值
sleep(秒数):程序休息,或者说是“睡眠”(需要引入头文件<windows.h>)
Sleep(毫秒数):注意与sleep之间区分大小写
system(“参数”):执行系统命令的一个函数(需要引入头文件<stdlib.h>)
参数:
shutdown -s -t 60:定时关机,时间为60秒以后
shutdown -a:取消关机
cls:清空屏幕
pause:暂停当前程序
sqrt(参数):开平方(需要引入头文件 <math.h>)
memset(字符串起始位置,‘填充元素’,从起始开始之后算的元素个数):memory(内存) set (设置)
注意:有点像字符串修改。
第二参数是int类型,不过由于ASCII码的存在,所以第二参数可以使用字符
c语言中数据类型:
char : 字符数据类型 (注意:字符需要用单引号) 1个字节
有符号位的char范围:-128~127
无符号位的char范围:0~255
short 或 short int: 短整型(整型之间存在空间上的区别) 2
int : 整型 4
long : 长整型 4
long long:更长的整型 8
float :单精度浮点型(注意后缀, 12.1f) 4
double:双精度浮点型(打印时用 “%lf”) 8
(浮点型注意后缀,以防精度丢失)
**注意:在c语言中整型的存储方式和浮点型的存储方式差异过大
变量的声明:
例:char ch=‘A’; (char ch;是向内存申请空间。=A,是对等号左侧进行赋值操作)
计算机中的单位:
二进制:正电 1 , 负电 0
bit - 比特位 1 个二进制位
byte - 字节 1个字节=8个bit =8个二进制位
kb 1个kb=1024个byte
mb 同上
gb
tb
pb
关于变量与和常量:
变量:可变的 (以下是变量的分类以及作用域和生命周期)
全局变量:定义在大括号{}外的变量,整个工程都可调用(整个工程结束后销毁)
全局变量不初始化,默认值是0;
局部变量:定义在大括号{}内的变量,出了大括号不可使用(出了大括号后生命周期结束)
局部变量不初始化,默认值是“随机值”;
常量(又称为“字面量”):固定的值,不可变的(常量的声明关键字const)
注意:整数常量可以带后缀,“U”和“L”,U表示无符号整数,L表示长整数(可大写,可小写)
字面常量:直观写出来的值,例: 100;
const修饰的常量:用const关键字修饰的常量,const(常属性),不可变,常变量(注意:本质上还是个变量)
例:const int num=100;
数组声明时,无法使用“变量、const修饰的常变量”,貌似只能使用字面常量
#define定义的标识符常量:#define(预处理器)
例: #define 名字 值(像是java中final常量)
关于宏:(感觉这个所谓的宏有点像常量)
#define 标识符 字符串
//define为宏定义命令
//标识符 为所定义的宏名称
//字符串 可以是常数,表达式,格式串等
宏分为 有参宏 和 无参宏:
有参宏的定义形式:
#define 宏名(形参表) 字符串
枚举常量:枚举(一 一列举),例:星期1、2、3、4、5、6、7
枚举声明关键字“enum”
例:enum 名字{ 值(字母组合)、值、值 }//里面的值都是枚举常量,他们有值,不可改(有点像是数据类型的声明)
使用: enum 上面名字 变量名 = 以上值
(有点像是一个选择列表,枚举的创建类似于选择列表的创建,使用时像是在列表内选择值)
注意:第一个枚举成员的默认值为整型的0,后续的枚举成员会在前一个成员上加1,逐渐自增。
关于字符串、转义字符、注释:
字符串:双引号引起的一串字符称为字符串字面值,简称“字符串”
存储字符串:支持使用 char 类型的数组(输出是直接输出数组)
例: char arr【】 =“abc”;//c语言支持字符串直接传入数组(注意:传入是会在字符串末尾加入“\0”而“\0”代表着字符串的打印结束,且“\0”的值是0,对照着ASCII表),但\0并不算字符串的内容
例: char arr1【】 = {'a','b','c',0或‘\0’};//不加\0,strlen()会产生随机值,直到遇到\0结束
转义字符:转变原来的意思(\0就是转义字符),转义字符代表的是一个字符
\n:换行符
\0:字符串结束符
\t:水平制表符,tab键
\?:书写多个问号时使用,防止被转移成三字母词
\ddd:ddd表示1~3个八进制数
\xdd:dd表示2个十六进制数
注释:
//:是单行注释
/* */ :多行注释,缺陷是不能嵌套
分支(选择)语句:选择结构
if:有else if,有else(注意:else只会匹配上一个if语句)
if(表达式)
语句;//符合条件,执行单条语句
if(表达式){
语句块;//符合条件,执行多条语句
}
switch:多分支语句,适合对比数值(表达式和值得数据类型需要相同)
switch(整型表达式){//整型表达式返回的是一个数值
case 值:
语句;break;
case 值:
语句;break;
default://都不符合时执行,默认值
}
循环语句:与java一样(break,终止循环。continue,跳过本次循环)
while(条件判断){
语句块;
}
while(条件判断)//执行单行语句
语句块;
do...while循环:特点是至少循环1次
do{
循环语句;
}
while(表达式);
for循环语法:初始化,条件判断,调整都可以省略
// 初始化 条件判断 调整部分
for(表达式;表达式;表达式)
循环语句;
for(;;;)//这是一个死循环
关于函数:用于实现某部分特定功能的一部分代码,具有特定的独立性
函数分为“库函数”和“自定义函数”
库函数:频繁使用某些功能,所以c语言加载了含有这部分功能的函数(使用库函数需要导入对应的#include 头文件)
自定义函数的创建:
返回值类型 函数名 (参数数据类型 参数...){
语句块;
return 返回值;
}
自定义函数的定义和导入:
定义:分为“.h”和“.c”文件,.h文件用于函数的声明,.c文件用于函数的定义
导入:在导入时,#include “文件名.h”,自己定义的函数导入时是用双引号“”来引起来的
注意:函数的声明必须在使用之前,使用从上到下的顺序,而函数的定义可以在使用之后。(声明与定义是两种不同的操作)
函数的声明:1,2,4可省略(1,2,4作用防止重复引用头文件)
#ifndef __TEST_H__ (注意:TEST_H 改成当前文件名大写,例:__ADD_H__)
#define __TEST_H__
int Add(int x,int y);//形参可以省略,但形参的数据类型不可以省略
#endif //__TEST_H_
注意:函数调用时,参数之间传递的只有“值”,函数调用之后,参数会开辟一块自己的内存空间,并不会影响到外界变量,除非传递的是“指针变量”
指针变量,所存的是所对应的内存空间地址,可以通过指针变量来明确的找到所对应的那块空间,并对其进行一系列操作
指针变量和“引用”非常相似,所存储的皆是某一块空间的地址
里面有“实参”和“形参”的概念
形参:形参只在函数内可以使用,函数结束后就会销毁(形参其实是实参的临时拷贝,且形参与实参没有任何联系,所以对形参的修改不会影响到实参)
实参:函数调用时所传递的值。(注意:实参传递给形参的只有值)
函数的调用:分为“传值调用”和“传址调用”
传值调用:形参和实参分别占有不同的内存块,所以对形参的修改不会影响到实参
传址调用:实参传递的是内存地址,而形参通过内存地址影响到外面的变量
注意:数组在传参的时候,传递的不是整个数组,而是数组的首元素的内存地址
注意 :函数内部无法求出形参数组的元素个数
注意:指针变量不可以直接用“*p++”这种自增符,因为++符号的优先级比*要高,所以会优先计算p++,而后才会将*算上
,可以采用小括号的形式“(*p)++”来重新规划优先级
链式访问:将函数的返回值作用于另一个函数的参数
示例:
printf("%d",strlen("dadsa"));
关于数组:数组是一组相同类型元素的集合(默认初始化为0)
数组的类型是:
数据类型 [值]
//可以使用sizeof
示例:
sizeof(int [10])//其中int [10]是数组的类型
注意:数组的下标从0开始,可以通过下标来获取对应的值
数组的创建:
数据类型 数组名[数组容量大小(值)] //可以不指定容量大小 (容量大小必须是“常量表达式”)
*****注意:数组的大小必须用 常量 来表示
关于字符数组:
字符数组的初始化可以是“字符串”进行赋值
**注意:字符串的末尾会有“\0”来做结束
数组初始化:
int arr[10]={1,2,3}//不完全初始化
char arr2[5]={'a','b'}//不完全
char arr3[5]="adsa"//支持字符串,\0也会存入数组内部
char arr4[]=“adsd”//可以不指定容量,会根据字符长度来规定容量大小,字符长度包括\0
通过取地址符&来获得下一个元素:
数组中的元素在内存中是连续存放的,它们的地址都是十六进制数,每两个相邻的元素之间的距离仅仅只有元素数据类型的所占空间大小(字节)
所以通过取地址符&获取元素后,可以通过 *****该元素的地址+该元素的数据类型大小=下一元素的地址*****
***注意:虽然函数的实参在传递数组时是数组第一个元素的地址,但是并不影响在函数内使用其数组的索引
数组名存放的就是数组首元素地址------但有两个例外
一:sizeof()中参数为数组,这个数组代表整个数组
二:&数组名:取出的是整个数组的地址(“整个数组”只是表面上的值看起一样)
函数数组参数:
一、int arr[];//传递的是数组第一个元素的内存地址
二、int* arr;
二维数组:外数组的元素是另一个数组
创建:
int a[10][5]={{1,2}};//二维数组初始化
int arr[3][2]={1,2,3,4};//二维数组不完全初始化,默认按顺序将第一行填满,4在第二行
[1] [2] [3]
[4] [] []
[] [] []
可以看做是一张“表”,以上“10”是行,“5”是列
int arr[行][列] //注意:行是可以省略的,列不可以省略
****也就是说离数组元素最近的大括号,它(数组)的容量必须指定
取值:与一维数组相同,可以通过索引来获取元素
关于操作符:
注意:操作符的优先级很重要!!!
算数操作符:+、-、*、/、%(注意:没有//整除的概念)
移位操作符:移的是2进制位(注意:仅作用于整数,不支持浮点数)
注意:不要移动负数位,这属于标准未定义
<<:左移
>>:右移
示例:
int a=1;
int b=a<<1 //2进制位左移一位
0000 0001
0000 0010
(前抹0,末尾加0)
右移操作符分为“算术移位”和“逻辑移位”:(是32个二进制位)
算术移位:通常使用的都是算术右移
右边丢弃,左边补原符号位(/2)
逻辑移位:
右边丢弃,左边补0
左移操作符:
左边丢弃,右边补齐(*2)
位操作符:2进制位操作
&:按位 与(符号两侧2进制位进行对比,取相同二进制位)
|:按位 或(进行对比,二进制位有1即使1,0、0才是0)
^:按位 异或 (非??)(二进制位相同为0,相异为1)
单目操作符:对单个数字进行操作
!
+(正值)
-(负值)
等等
&:取地址符
*:解引用操作符
sizeof:获取内存大小
++:自增符号(数字在前 ,先+1,然后使用该值。数字在后,先使用,再+1)
--:自减符
(数据类型):强制类型转换
示例:
int a=(int)3.14;
~:对一个数进行按位(二进制位)取反
例: ~x
010101(计算机存储数据存放的是补码,需要求原码,首位为符号位)
101010
关系操作符:
>
>=
<
<=
!=:不等
==:判断相等
逻辑操作符:
&&: 逻辑与(表达式&&表达式)注意:第一个表达式如果为假,则后一个表达式不会进行运算
真&&真 为真,其他为假
||: 逻辑或
真||假 为真, 假||假 为假
(注意:第一个表达式为真,则后一个表达式不会进行运算)
条件操作符:(三目运算符??)
条件表达式?结果1(true):结果2(flase)
逗号表达式:从左向右依次计算,整个表达式的结果是最后一个表达式的结果
表1,表2...
int c=(a>b,a=b+10,a,b=a+1);
下标引用、函数调用和结构成员:
[]:下标引用操作符,调用数组元素是使用
示例:arr[索引];
():函数调用操作符,使用函数时,函数后面的小括号就是“函数调用操作符”
. :结构体变量.成员
结构体初始化可以使用{}来进行初始化
struct 结构体名字 对象名={初始化信息,...};//创建对象,并初始化信息
//struct 结构体名字,在这里是“数据类型”
->:结构体指针指向操作符
结构体变量指针->成员;//可以获取当前指针所代表的对象的成员数据
解引用操作符:*被称为“解引用操作符”或“间接访问操作符”。
*指针变量 ; //访问指针变量内 存的地址所在空间
//更像是从内存空间内取值的一个操作
原码、反码和补码:
注意:符号位(二进制首位)为0是“整数”,符号位为1是“负数”
只要是整数,内存中存储的都是二进制的补码(二进制位为 32位)
正数 ---- 原码,反码,补码 都相同(存的也是补码)
负数 ---- 补码
原码得到反码:符号位不变,其他二进制位取反
原码得到补码:原码的反码+1,得到补码
反码:补码减1的号反码
指针:(关于地址去看最上面“扩展”)
&数组名时,取到的是整个数组的的地址
++和--的优先级要比*(解引用符号要高)
注意:指针创建之后尽量进行初始化,如果没有初始化的对象,那就赋值NULL(空指针),使用不到指针时注意将指针置为NULL
NULL:空值(空指针)
指针变量:指针变量存储的是“地址位”(二进制序列号)(电脑32或64位,影响着一个指针变量的大小,32位:指针变量是4个字节,64位:指针变量占8个字节)
示例: int* p=&a;//int* 是指针变量的数据类型,且必须与a的数据类型一样 ,*声明这是个指针变量 ,& 取地址符
*p =20;//通过“*p”找到那块内存空间,来对那块空间进行操作
*:被称为“解引用操作符” //更像是从内存空间内取值的一个操作
指针变量类型的意义:
因为指针变量内存放的是“地址”,所以可以不用在意指针变量的类型,但是,在对那块“内存空间”进行使用时(解引用操作),你的指针类型代表着可操作的字节数量
指针类型指针进行解引用操作的时候,能够访问空间的大小
int*p; *p能够访问4个字节
char*p; *p 能够访问1个字节
double* p; *p能够访问8个字节
指针加减运算:(指针+-整数、指针-指针、指针的关系运算)
指针(地址)加1
指针类型决定了指针走一步走多远(指针的步长)
int*p: p+1-->4 //这里的1代表着指针数据类型的大小
char*p; p+1-->2 //1是加1步,步长为指针变量的数据类型大小
idouble* p; p+1-->8
指针减去指针得到的是中间的元素个数
野指针:指针没有进行初始化,里面放的是一个随机值(随机地址)
使用时会导致内存空间的不确定
数组在使用“指针++”的时候,一但超出指针管理的范围,之后的指针都是野指针。
int arr[10]= { 0 };
int *p = arr;
int i = 0;
for (i = 0; i< 12; i++){
p++;
}
关于二级指针和一级指针:(允许存在三级指针)
一级指针:指向变量的指针
二级指针:指向指针的指针(二级指针内存放的是一级指针的内存地址)
声明方式:
int** pp=&p//p是一个指针,pp是个二级指针,查看“*”的个数可以了解到这是几级指针
也可以理解为最后一颗“*”之前的是当前对象所存值得数据类型
注意:在解引用的时候也需要注意到“*”的个数
指针数组:存放指针的数组(支持多级指针数组)
声明方式:
int* arr[10];//指针数组示例
数组指针:指向数组的指针,可以存放数组的地址(&arr)
声明方式:
int (*p)[值]=&arr;//与指针数组有所区别,优先级很重要
//int是数组指针的类型,与等号右面的地址所属值类型相同
//*
关于函数指针:指向函数的指针,可以和一般函数一样,调用函数,传递参数
注意:函数也拥有地址,可以使用&取地址符,函数名和&函数名都是函数的地址
函数地址的存储:
//这是一个返回值为int类型,两个参数都是int类型的函数
int (*p)(int,int)= 函数地址
/* int 代表着函数的返回值类型(如果函数返回值类型是void,也需要加上)
(*p)表示这是一个指针 //p同时也是函数指针的变量名
(int,int)表示函数参数类型,形参可加可不加
函数地址:可以使用&,也可以使用函数名
int (*)(int,int) 不加变量名,代表着函数指针类型
*/
调用函数指针:
可以直接使用指针变量,也可以对函数指针进行解引用,来调用函数
关于函数指针数组:存放函数指针的数组(又叫转移表??)
示例:
//函数指针数组的声明
int(*函数指针数组的名字[数组容量])(函数参数类型);
/*
其中 int (*) (函数参数类型) 代表着数组元素的数据类型
*/
//初始化
int(*函数指针数组的名字[数组容量])(函数参数类型)= {函数名,函数名}
或者
函数指针数组的名字[数组容量]={函数名,....} //已经提前声明好函数指针数组
调用函数指针数组:
函数指针数组的名字[索引index](函数参数)
关于指向函数指针数组的指针:该指针指向函数指针数组
示例:
//函数数组指针的声明
int (*函数指针数组的名称[数组容量])(函数指针数组元素的函数参数类型);
//指向函数数组指针的指针
函数数组指针的返回类型 (*(*指针名称)[数组容量])(函数指针数组元素的函数参数类型)= &函数指针数组的名称
//指针名称 是一个指针数组,且数组有n个容量
//每个类型 是 返回类型 (*) (函数参数类型)
关于结构体(感觉类似于对象):自己创造出来的一种数据类型,需要用到关键字“struct”
结构体的创建:
示例: struct 结构体名{ // 有点像“类”
char name【20】
....
语句块
}
结构体的使用:
int main(){
struct 结构体名字 变量名={“对结构体内的第一个变量进行赋值”,“第二个”,“.....”}
//以上是“对象的初始化”
}
//在打印的时候,可以使用 对象名 . 内部变量。
//赋值的时候也可以使用 对象名 . 内部变量 的形式。//变量可重复赋值,数组不可以
注意: “struct”不能丢
通过指针访问对象内的数据:(说是对象仅方便理解)
printf(“%s\n”,(*指针变量名). 成员)//运用对象的用语,仅方便理解
printf(“%s\n”,指针变量->成员)//与上一句相同结果
结构体内的数组成员:需要使用strcpy(函数),字符串拷贝
进行赋值:
strcpy(对象名.
成员名,“要拷贝到结构体数组成员的值”);
关于有序数组的查找元素(最适合使用二分法查找,或者叫做“折半查找算法”):
遍历数组的方式效率较低,
二分法查找算法:取中间的值,进行比较,如此循环,直到找到符合条件的元素
数组的“首元素”和“尾元素”的索引相加,并且除以2,得到的是中间元素的索引
goto语句:(如非必要,不建议使用) 无视规则,跳转到标记地点
goto(去哪里)
goto 标记;(随意一个名字)// 标记声明
标记: //标记使用(直接跳转到标记后面的语句)
缺点:代码执行顺序被打乱(出现bug时,你可能会很懵)
优点:1.适合处理错误情况
2.适合多层循环嵌套,且使用break跳不出时,可以选择使用goto语句
关于递归:程序调用自身
主要思考:将大事化小
必要条件:存在限制条件,当满足这个限制条件,递归不在继续
每次递归调用之后越来越接近这个限制条件
注意:递归需要有限制条件,不然会出现stack overflow错误(栈溢出)
关于栈、堆、静态区:
栈:局部变量、函数形参(函数申请都在栈区)
堆:动态开辟的内存
静态区:全局变量、static修饰的变量
关于复合语句:
在函数内部再次使用大括号
示例:
void main(){
{
int a=11;
}
printf(“%d\n”,a);//无法调用到a变量
}
关于c存储类:
auto:auto存储类是所有局部变量默认的存储类
int a;
auto int a;
//注意:只能在函数内使用,且quto只能修饰局部变量
register:用于定义存储在寄存器中的而不是RAM中的局部变量(并不是一定将变量存储在寄存器中,只是可能,取决于硬件和实现的限制)
register int miles;
static:使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
extern:引入外部文件变量
扩展:
无符号数和int类型相除,以无符号数为标准进行相除
//%f(默认输出小数点后六位)
双精度浮点数,小数点后占六位,且拥有四舍五入
printf(“x=%10.3f\n”,x);//这里的10.3代表总共占10位,小数点算一位“.3”表示小数点后占3位,不够整数前面补空格
printf(“x=%-10.3f\n”,x);//-10.3,与上相同,但小数后面补空格
*****//当宽度也就是上面的10,小于实际数字的宽度,就会取默认情况,小数点前原样输出,小数点后默认为六位
printf(“%.3s\n”,“student”);//结果为stu,“.3”代表精度,意思是取字符串三位,s为格式化输出
//以上“.3”代表精度,“10”代表宽度
回文数:将数子逆序等于其本身(逆序==本身)
例如:12321 //回文数,逆序结果为12321
基础知识之c的特点:
语法检查不严格,程序设计自由度大
允许直接访问物理地址,能进行位操作
具有结构化的控制语句
c的构成:
1.一个c程序可以有一个或多个源文件(.c文件 )构成,一个源文件是一个编译单位
2.c程序是由函数构成的,一个c程序可以有多个函数,但必须有且只能有一个主函数
3.一个函数有两部分构成:函数首部和函数体
4.一个c程序总是从主函数开始执行,结束于主函数,与主函数的位置无关
5.主函数能调用用户函数或系统函数,用户函数可以调用彼此,但是不能调用主函数
6.注释:不会被编译执行
单行注释 //
多行注释 /*注释内容*/
7.语句以分号结尾
一行可以写多条语句
一条语句可以写多行
8.区分大小写
//一个c源程序必须包含一个main函数
数据类型:
基本类型: 16位机(所占字节数) 32位机
整型:
有符号数:
短整型:short 2b
整型:int 2b 4b
长整性:long 4b
无符号数:
unsigned int
实型:
单精度型:float 4b
双精度型:double 8b
字符型:
有符号数:char 1b
无符号数:unsigend char
枚举:
构造类型:
数组:
结构体:
共同体:
指针类型:
空类型:void
常量,变量,运算符,表达式:
//后缀:l或L 长整型 , U或u 无符号数
1.标识符(大小写敏感)
组成:字母,数字,下划线的组合
开头:字母,下划线
//注意:c语言关键字不能 用作标识符
//预处理命令 能用作标识符
如:include,printf,define
2.常量
整型常量:
八,十,十六进制
八进制:例 04,075 // 前缀为0 + 0~7
十进制:无特殊要求, //长整型 加后缀 123L
十六进制:例 0x5A,0x43 //前缀为0x(x不区分大小写)+ 0~9,A~F
实型常量:(必须带小数点,可省略前或后的0)
//浮点数又叫实数,实型
十进制形式:8.14,-7.9,.12
指数形式:不区分e的大小写
//注意:e前e后必有数 ,e后为整数
1.23E-2(小数点向左移动两位),43.5e+6(小数点向右移动六位)
字符常量:
用单引号括起来的普通字符或转移字符
普通字符:‘a’,‘b’
转义字符:‘\n’
以反斜线开头,放在 一对单引号内
‘\n’:换行
‘\t’:下一个制表位
‘\r’:回车
‘\b’:退格(将光标向前移动一个位格)
‘\"’:“
‘\'’:‘
‘\\’:\
‘\bbb’:可跟1~3位八进制
示例 ‘\101’:转换成十进制65,根据ASCII表,65为字母'A'
‘\xhh’:1~2位十六进制
‘\0’:字符串结束符
字符串常量:用双引号括起的字符序列
“a”,“ab”,“”(空字符串 )
字符串结束标志:每个字符串尾部自动加一个‘\0’
"\0":字符串结束标志
符号常量:用表示服代表常量
#define PI 3.14 //将3.14赋值给PI这个标识符,注意标识符尽量大写
符号常量的值在其作用域内不能改变,也不能 另赋值
地址常量:
当数组在定义时,数组名为其首地址
3.变量
变量初始化:定义变量时,对变量赋初值
//如果没有进行初始化,其值为“随机数”
4.运算符及表达式
强制类型转换运算符
(类型名)表达式
赋值运算符及表达式
简单的赋值运算符
变量名 = 表达式
复合赋值
a+=表达式 ....
略
自增自减运算符及表示式
//注意:自减自增运算符只能对变量进行操作,不能对常量和表达式操作
//该符号位于变量前后,意思各不相同
//符号在变量前,先计算后赋值
//符号在变量后,先赋值后计算
++:自增
--:自减
逗号运算符及表达式
一般形式:
表达式1,表达式2,表达式3...
//过程:表1--->表2--->表3--->....
//逗号表示式的值是最后一个表达式的值
关系运算符及表达式
< <= > >= == !=
//关系表达式 的值为一个逻辑值
//真用‘1’表示,假用‘0’表示
逻辑运算符
!: 非 //注意:!x 等同于 x==0
&& :智能与
||:智能或
//运算符:所有非0值为“真”,0表示“假”
//**短路规则:
“当有足够条件确定表达式的值后”,剩余部分将不会被计算
条件运算符及表达式(三目运算符)
一般形式:
表达式1?表达式2:表达式3
//表1执行结果为真,执行表2
//表1执行结果为假,执行表3
位运算符
对字节或字内的二进制位进行操作
位运算符的运算对象只能是整型数据或字符型数据
//运算对象一律按“二进制补码”参加运算,并按位进行运算,
//所以不可以是 实型,也就是浮点数
位运算的结果是一个整型数据
位运算符:以下优先级,由高到低
~:按位取反
<<:左移位
>>:右移位
&:按位与
^:按位异或
|:按位或
单目运算符(????)
. -> () [ ]
! ++ -- + - * &
*****注意:%该运算符的运算对象只能是整数(左右两边必须是整数)
编程部分
程序结构分为:顺序结构,选择结构,循环结构
头文件:
stdio.h :定义了输入,输出函数
string.h:定义 字符串函数
math.h:定义 数学函数
标准输入/输出函数:
putchar:输出字符
printf:格式输出
puts:输出字符串
-----------------
getcahr:输入字符
scanf:格式输入
gets:输入字符串
数学函数:
sqrt(非负实数):平方根函数 ,返回值类型是Double
fabs():绝对值函数
二、格式输入输出函数
1.格式输出函数
printf(“格式控制字符串”,输出项表列);
//格式控制字符串分为两部分:普通字符,格式控制符(%)
格式说明符:
d 以有符号的十进制形输入出整型
c 以字符形式输出,只输出一个字符
s 输出字符串
f 以小数形式输出单,双精度数(默认输出小数点后六位)
o 以8进制无符号形式输出整数
x 以16进制无符号形式输出整数
u 以无符号10进制形式输出整数
2.格式输入函数
scanf(“格式控制字符串”,地址表列)
//格式控制字符串分为两部分:普通字符,格式控制符(%)
//需要用到&取地址操作符
//scanf函数,回车就表示结束输入了
//*****输入时需要严格按照“格式控制字符串”来输入
//支持设置接收宽度 例:scanf(“%2d %2d”,&a,&b) %2d:接收2位整数
//如果本身宽度大于设置宽度,按本身输出
//*****如果没有接收到值,系统会产出随机数并赋值
//*****不能规定精度 例:%5.2f (x)
格式
%d 整数
%c 字符(空格也是一个字符)
%s 字符串(输入时遇到空格或者回车符会结束输入)
%o 八进制输入整数
%x 十六进制输入整数
%f 浮点数(默认输出小数点后六位)
%lf 输入double型数据
%*d 输入一个数,但是忽略它
三、字符输入输出函数
1.字符输出函数
一般形式 putchar(ch); //ch是char类型变量
一次输出一个字符
putchar(‘A’);
putchar(char c):字符输出函数,参数为char类型
2.字符输入函数
一般形式 char ch=getchar();
//getchar():只能接收一个字符,无参数
循环语句和选择语句:
if
else if
else
switch(表达式){ // 表达式必须是int或者char类型
//注意case穿透现象
//case后面的大括号{}可以不加
//每个case后的常量表达式各不相同
case 常量表达式:
语句;
break;
default:
语句;
break;
}
while(表达式){ //先判断表达式条件,后循环
循环体;
}
do{ //先循环,后判断条件,至少循环一次
}while(表达式);
for(表达式1;表达式2;表达式 3){
循环体;
}
//表达式1:循环变量初值
//表达式2:循环结束条件
//表达式3:改变循环变量值
//循环体可以省略,并将 循环体的内容放在表达式3的位置
例:for(i=1;i<=100;s+=i,i++)
//表2省略,相当于此处为1,恒真
//*****分号不可以省略
break和continue语句
break:跳出本层循环或switch
continue:提前结束本次循环,进行下一次循环判断
关于数组:
//数组内的元素在内存中的存放是:连续存放的
//数组名代表的是数组首元素的内存地址
//数组名是 地址常量
一维数组
定义:数据类型 数组名[长度] //长度必须是常量或者常量表达式(必须是整型)
一维数组元素的引用(也就是索引)
数组先定义,后引用
引用:数组名 [下标] //下标从0开始,范围是0~数组元素个数-1
//支持常量,变量,表达式
数组的初始化
int a[5]={1,2,3,4,5};
int a[]={1,2,3,4,5};
int a[5]={1,2}; //部分初始化,其他未初始化的元素默认为0
int a[5]; //未进行初始化,元素为随机数
//初始化时中括号的长度可以省略
二维数组:
定义:数据类型 数组名[长度1][长度2] //长度皆为整型常量
行数 列数
按行连续存放,是特殊的一维数组
二维数组元素的引用
数组名[下标1][下标2];
初始化:*****初始化时行数可省略
int a[2][3]={{1,2,3},{4,5,6}};
int a[][3] //初始化时行数可省略
//按存储顺序存放
//注意:****不允许省略第二维度
//一般用双重循环处理二维数组
字符、字符串操作常用函数:注意,当定义完字符数组之后,无法再将字符串赋值给其变量,只能通过函数赋值
字符串的输入/出函数
gets(地址);
gets(str); //str是一个数组,又代表数组首元素地址
puts(地址);
puts(str);
//*****字符串初始化(注意:定义时要多加一个\0的位置)
//数字0和"\0"一样,“\0”的ASCII码是0
char c[5]={"adsa"};
char c[5]="adsa";
//部分初始化,其余剩余部分是0或者“\0”
char c[5]={'a','b'};
字符数组
定义:char 数组名[长度];
//逐个字符初始化
char c[4]={'a','b','\0'};
字符串连接函数
//将两个字符串连接,并赋值给“地址1”
//将地址2中的字符,复制到地址1末尾字符和"\0"的中间
//注意:地址1的长度要足够大,多余空间可以容下地址2的字符
strcat(地址1,地址2);
字符串复制函数
//将参数2,复制给参数1,(复制过去会直接覆盖)
//注意:复制时连“\0”一起复制
//字符串只能使用strcpy函数赋值
strcpy(地址,串);
//注意:不能用赋值语句直接给字符数组赋值,但是数组初始化是支持的
例:char s[10]
s="abc"; (x)//错误
//因赋值操作只能是变量操作,s是一个数组,代表数组首元素地址,是一个常量,无法进行赋值操作
字符串长度函数
//****该函数在计算字符个数时,是不包含"\0"的
//****注意:计算时遇见“\0”结束计算,遇见“\0”,先查看是否是八进制,如果不是才是“\0”
//计算时是从“参数地址”开始计算,直到遇见“\0”结束
strlen(字符串或指针或地址);
字符串比较(底层比较的是字符的ASCII码)
strcmp(字符串1,字符串2);
字符串1>字符串2,返回值>0
= =0
< <0
函数:
编译 链接
源程序文件.c-------->目标文件.obj--------->可执行文件.exe
定义:完整独立的单位,指定函数类型名,形参的类型,函数体
数据类型 函数名(形参表列){
声明部分
执行部分
}
//数据类型是函数的返回值类型
//*****注意:函数必须先定义或声明才能被调用
声明:对函数类型,函数名称,形参类型个数通知编译系统,是一条语句,以“;”结束
//*****必须出现在被调用之前,可以在main方法之内,可以忽略形参,但是形参类型不可以忽略
函数声明示例:
int max(int a,int b);
int max(int , int);
关于实参和形参
实参:出现在函数调用中,将实参的值传递给形
形参:出现在被调函数中
//实参和形参个数相同,类型兼容
*****main是由系统调用,main可调用库函数(如,stdio.h,math.h),自定义函数
函数定义:完整独立的单位
指定函数类型名、形参的类型、函数体
函数声明:对函数类型、函数名称、形参类型个数通知编译系统、是一条语句,以“;”结束
函数参数传递方式
1.单向的值传递
实参为常量,普通变量,表达式时,随调用,随分配,用完就释放
实参和形参占不同的存储单元(单向传递)
//实参和形参可以同名
2.“双向”地址传递
实参是地址:数组名,指针变量
函数的嵌套调用,递归调用
//注意:不允许嵌套定义函数
函数调用函数本身
递归调用:一个函数直接或间接调用它自己
变量的作用域与生存期
1.作用域:变量起作用的范围
局部变量:在函数内定义的变量,作用域在本函数内
形参:内部变量
特点:随用随分配,用完就释放,未赋初值,是随机数,在并列语句块中变量名可以相同
//在main()定义的变量也是局部变量
全局变量:在函数外定义的变量
作用域:从定义点开始到本源程序文件结束
特点:全局变量与局部同名,内部优先
//注意:未赋初值,默认为0
可以使用extern将全局变量的作用域扩大
2.变量的生存期
指变量是否还拥有内存单元
静态数据区:全局变量,静态局部变量
定义时分配,初值为0,程序结束时释放
初始化只执行一次
动态数据区:自动变量(内部)
随用随分配,用完就释放
初值为随机数
初始化执行多次
存储类别:
auto:默认存储类别
static:静态
extern:外部
register:寄存
指针:变量的地址
变量两个物理定义:变量值和变量地址
指针变量:放地址的变量
指针变量定义:
int a,b,c,*p;
a=3;b=5;
p=&a; //将a的地址存放到指针变量p中
*p=b+c; //*p代表p指针变量中地址内存中所代表的值
指针变量赋值:
int a,*p=&a;
int a,*p; p=&a;
//未赋值的指针变量,叫做“野指针”(指针悬挂)
指针变量一定要有明确的指向
*****指针变量只能指向与它数据类型相同的变量
两个运算符:
(*****优先级相同,右结合,自右向左进行结合)
&:取地址
*:指针运算符,地址解析(与指针变量连用,取出指针变量中的值)
//****注意:指针所占字节数与数据类型无关
TC:占2个字节
VC:占4个字节 (vc:windows下)
原则:
地址=指针
永远清楚每个指针指向了哪里
永远清楚每个指针指向对象的内容是什么
永远不要使用未初始化的指针变量
注意:指针 减 指针,得到的结果是一个int类型的值
按值传递调用:形参改变,不影响实参
//普通变量
按地址传递调用:形参改变,影响实参
//实参:数组名,指针变量
指针和数组:
数组的指针:数组的首地址(常量)
数组元素的指针:数据元素的地址
指向数组的指针变量,该指针变量当数组名使用
例:
a是数组名,数组的首地址
a+1代表&a[1]
a+i代表&a[i]
*(a+1)代表a[i]
//函数调用时,数组传递的是地址首元素,函数接收的是数组首元素地址
指针和二维数组:
int *p,a[3][4];
p=&a[0][0]; //或 p=a[0]
-------------------------------------
&a[i][j]=a[i]+j=*(a+i)+j=p+i*m+j
a[i][j]=*(a[i]+j)=*(*(a+i)+j)=*(p+i*m+j) //m这里指每一行的元素个数
字符串指针:
可以将字符串直接赋值给字符串指针
(地址为字符串首元素地址)
指针变量是变量,字符数组名是首元素地址,是常量,常量不可改
函数指针和指针函数:略
编译预处理命令:
#开头 单独占一行,尾部不加分号
宏定义:注意,宏定义在使用时,是按照定义时的样子,(*****原样替换)
//*****不带参数的宏定义
#define 标识符 字符串
// 宏名(大写) 不加“”
例:#define PI 3.14
NULL = 0 (c语言中硬性规定)
EOF = -1
//*****带参数的宏定义
#define 宏名(参数) 字符串
例:#define SQ(n) n*n
文件包含:一条include语句,只能包含一个头文件
#include <文件名 > //.h文件
#include "文件名" //.c文件
先去当前项目目录下检索,再去标准目录下检索
结构体和共用体:
结构体://有点像对象
struct 结构体名{
成员;
};
结构体变量的定义:
1.先定义结构体,再定义变量
struct stu a;
2.定义结构体同时定义变量
struct stu{成员;} a; //a是结构体变量
3.不定义结构体名,同时定义变量
3.结构体变量的初始化
struct stu a={“张三”,96,95,90};
struct stu{
.....
} a={“张三”,96,95,90};
4.结构体成员的引用
变量.成员 (*指针).成员 ...
//对结构体变量整体只能赋值,不能整体输入,输出
共用体:
共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
//*****任何时候只能有一个成员带有值
//*****所有成员共用同一段内存单元
1.定义:
union 共用体名{
成员;
};
2.共用体变量的定义
(1).先定义共用体,在定义共用体变量
(2).定义共用体,同时定义共用体变量
(3).不用共用体名,同时定义共用体变量
3.共用体变量占内存
union m{
char i;
int j;
float k;
//&a=&i=&j=&k
} a;
4.成员引用方法
变量.成员 (*指针).成员
//*****保存的是最后一个赋值
5.*****共用体变量不能初始化,若初始化只能对第一个成员初始化,不能作函数的参数
三、用typedef定义类型(有点像是在起“别名”)
不产生新的类型,只是将已有类型改名
typedef 旧名,新名
关于*和++的优先级:
左++>*>右++
注意:汉字一般占用计算机的两个字节