一、运算符
int iNumber=2;
0&&(iNumber=3)
执行之后还是2
在计算机里面非零为真,0为假
逻辑运算与关系运算返回值为0或1
按位运算符(数学值)
& 有零则 0
| 有1则 1
~ 非
^异或 同则0不同则1 每一个二进制位按相同为零,不同为一的运算方式
特殊运算符:
Int 4
Float 4
Double 8
Short 2
Char 1
sizeof()
Sizeof(“I Love You”)统计字符串字符个数包括\0 11
a>b?a:b
(a>b?a:b)>c?(a>b?a:b):c
二、文件操作:
相对路径 :从当前项目开始搜索找到文件 ./file.txt
绝对路径:从计算机盘符 F:\\file/123.txt
打开文件:
函数原型 File* fopen(char* filename,char* mode);
返回文件指针类型,如果打开文件失败返回NULL
File* fp;
Fp=fopen(“file.txt”,”w”);
打开文件的几种方式
r只读 (普通文件)
w 只写的方式打开文件,如果没有该文件怎创建该文件,注意如果该文件中有文件那么会把文件中的文件清空(普通文件)
a追加
r+ 读和写 (普通文件)
W+读和写和r+一样的功能(普通文件)
a+ 读和追加(普通文件)
对二进制操作的打开方式
rb wb ab rb+ wb+ ab+
打开文件失败的几种情况:
1、以r只读的方式打开
2、使用绝对路径打开的文件路径不存在
3、要打开的文件被其他程序所占用
关闭打开的文件:
函数原型: int fclose(File* file);
参数文件指针
返回int类型
关闭失败返回EOF(一个宏定义值是-1)
成功返回0
作用:保存数据,关闭文件
F12查看定义
exit(0/1/2)直接结束程序相当于主函数中的return 0 ;语句
文件的输入输出:
1、向文件中写入单个字符fputc();
函数原型: int=fputc(int ch,File* file);
使用while循环和fputc()函数实现写入一串字符串
While((ch=getchar())!=’#’)
{
Fputc(ch,fp);
}
从文件中读取数据
2、fgetc();从文件中读取一个字符
函数原型:int fgetc(File* file);
Char ch;
While((ch=fgetc(fp))!=EOF)//每个文件最后都有一个EOF,使用EOF检验文件数据是否读取完毕
{
Putchar(ch);
}
将字符串写入到文件中去
3、fputs();
int fputs(char* str,FILE* file);
从文件中读取一串字符串
fgets();
4、函数原型:char* fgets(char* Buf,int MaxCount,FILE* file);
从file文件中读取maxcount个字符到Buf中,并且Buf的最后一个字符是’\0’
5、fprintf();向文件中格式化写入数据
fprintf(“%s ,%d ,%c”,str,age,ch);
6、fscanf();从文件中格式化读取数据
fscanf(file,”%s %d %c %d”,str,&age,&ch,&num);
7、fread(file,5,3,str);
从file文件中每次读取5个字符,共读取三次,将所有的字符保存到str字符串中去
8、fwrite(str,5,2,file);
以什么方式写进去就医什么放是读出来
向file文件中写入str字符串中写入每次5个字符共写入2次的操作
9、ftell(fp);获取当前文件内部指针的位置
10、rewind(fp);将文件内部指针指向文件的头部
11、fseed(fp,偏移量,起始点);
将内部指针从文件头或者当前位置或者文件尾偏移几个单位
起始点的值只可以为0--- 文件头部 1 ---当前位置 2 -----文件末尾
偏移量类型是长整形 必须写成 5L
如果起始点是0(头部)那么偏移量不可以为负的
2(尾部) 正
fwrite(str,5,2)函数 当以r+的方式打开文件执行该函数时,会把文件中同样位置的字符替换,如果从str字符串中读取5个字符时,如果这五个字符中间有空格,会将写入的字符串截断,只会写入空格之前的字符,空格之后的字符会全部用空格代替
fprintf()以r+的方式也会将相同位置的字符替换
Fputs()以r+的方式写入数据也是会把相同位置的字符替换的
Fputc()以r+的方式写入数据也会替换并且如果替换的该位置是文字,写入字符后面的文字会乱码
★★★★★使用w w+方式打开文件都会将文件清空★★★★★
a+的方式,写入的时候是从文件尾写入的(即使在写入前改变了内部指针的位置也是无效的)
使用a+的方式打开文件之后如果是直接进行读取文件那么是从文件头读取的
Fopen()-------------fclose()
Fputc()--------------fgetc()
Fputs()--------------fgets(); 从这都有字符串参数
Fprintf()-------------fscanf()
Fwrite()-------------fread()
fseed()--------rewind()--------stell()
如果在写入文件之后内部指针指向了文件末尾,这是再读取数据就会出现好多屯
解决方法就是使用rewind将指针重新指向文件头部
写入文件的时候如果是最后一行,不要加换行,不然在取出数据的时候就会取出一条空的数据,得到的就是好多屯屯屯。。。
文件指针是按字节数进行移动的,一个中文文字占两个字节
三、随机产生数:
Srand((unsigned in)time(NULL));//中下随机数种子
Rand();随机产生一个数;
使用取余%---------产生一定范围内的数字
%100肯定只能产生0-99之间的数嘛
如果要产生50-100之间的数,先产生0-50之间得数,然后在+50不就行了
Rand()%51+50;
数组指针:指向数组的指针 int (*a)[4]
指针数组:存储指针的数组 int* a[10]
指针函数:
Type* fun(){}
返回某一类型的指针的函数
四、排序:
稳定性:如果一组数据中有相同的元素 A,B,排序前A的位置是在B位置的前面,经过排序之后,A的位置仍然在B的位置的前面,那么这样的排序就成为稳定的排序算法。只要有一组关键字实例发生了类似的情况,就可认为这种算法是不稳定的
内排序和外排序:
根据在排序的过程中带排序的记录是否全部放置在内存中,排序分为内排序和外排序,内排序是指待排序的所有记录全部被放置在内存中,外排序是由于要排序的记录个数太多,不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能进行。
对于内排序,排序算法的性能主要受三个方面影响:
1、时间性能(判断和交换的次数越少,算法性能越好)
2、辅助空间(辅助内存的开拓)
3、算法的复杂性(不是指的算法的事件复杂度,是指的算法本身的复杂度)
七种排序:
按照算法的复杂度分为两类:
简单排序:冒泡,选择排序,插入排序
改进排序:希尔,堆,归并,快速
1、冒泡排序:
基本思想是,两两比较相邻记录的关键字,如果反序则交换
最简单的:
这样的排序是属于交换排序思想,并没有进行相邻两两比较
如果出现这样的 2 3 4 6 5 7 8 1 极端数据
经过第一番排序之后,虽然讲最小的1排在了最前面,但是貌似对其余的元素没有什么帮助,反而还将第二小的数字2放在了最后面(因为是直接交换了),这个算法效率是非常低的。
冒泡排序:
void Bubble_Sort(int arr[],int len)
{
int tempVal;
for(int i=0;i<len-1;i++)
{
for(int j=0;j<len-1-i;j++)
{
if(arr[j+1]<arr[j])
{
tempVal=arr[j+1];
Arr[j+1]=arr[j];
Arr[j]=tempVal;
}
}
}
}
因为是两两相邻比较的,所有会将关键字一直往上面冒,直到遇到不满足if条件,之后在找到下一个关键字,网上冒,这样执行一轮之后不但将最小的数冒到了最上面,而且也将下面较小的数往上面移了,这样效率就有了很大的提高
冒泡优化:
如果出现了这样的情况
2 3 4 5 6 7 8 9 1,这样的情况 j从后面一路判断过来都没有交换数据,那么肯定i后面的元素已经是有序的了,就不在进行相邻的数据比较了
冒泡排序时间复杂度为O(n^2)
2、选择排序:
冒泡排序和简单选择排序可以用买股票的两种类型做类比
冒泡就是在不断的进行比较交换,相当于炒股票是不断的买入卖出,买入卖出,有的人就是抓准时机,只进行一次的买入卖出,简单选择排序就相当于第二种人,只交换一次就确定了关键字在顺序中的位置(定位)
简单选择排序相对于冒泡只是交换的次数减少了不少
简单选择排序时间复杂度O(n^2)和冒泡一样,但是在性能上要略优于冒泡的还是
3、插入排序:
插入排序是将无序数据一个个插入到一个已经排好序的序列中去,这样进行遍历一遍之后就有序了,最好的适用情况是序列基本有序元素个数较少,然后只需要将位置不对的元素进行插入到合适的位置就好了,效率很高
优化排序算法:
希尔排序:
void Shell_Sort(int arr[], int len)
{
int tempVal;
int j;
int jump = len / 2; //不一定都是除以2
while (jump != 0)
{
//下面的操作就是将按照跳跃式分好的组进行插入排序操作
for (int i = jump; i < len; i++)
{
tempVal = arr[i];
j = i - jump;
while (j >= 0 && arr[j] > tempVal)
{
arr[j+jump] = arr[j];
j -= jump;
}
arr[j + jump] = tempVal;
}
jump = jump >> 1;
}
}
希尔排序的高明之处就是将序列进行跳跃式的进行分组,之所以要分组的原因是为了迎合快速排序的特点(元素个数较少,元素基本有序),然后将每一组每一组的数据进行比较排序,这样做的结果就是序列看起来基本是有序的,所谓基本有序就是小的基本是在前面,大的是在后面(按照升序排列情况),最后当jump等于一的时候,这时序列基本是有序的,将整个基本有序的序列进行最后检查,将特别的位置不对的元素进行很少的调整位置就可以排好序了,这样进行最后排序之后就排列好了
桶排序(也叫基数排序)
如果排序的是数字没有哪一种排序算法比桶排序效率要高
桶排序只能针对整数数值进行排序,而且对要排序的序列要求还有几个
桶排序虽然时间复杂度是最小的,但是空间复杂度是最大的,因为它需要使用一个二维数组来对要排序的元素根据个十百千位等等上的数字来放在二维数组中
如果要排序的数中最大的数是1000,那么就需要使用一个10行,100列的二维数组来最为辅助空间
//桶(基数排序)//辅助空间占用比较大
void Bucket_Sort(int arr[], size_t len)
{
int tempArr[10][10]; //这样写最多可以排10个数
for (size_t n = 1; n < 1000; n *= 10) //这样写表示要求数组中的最大数不能大于1000
{
//将临时数组全部初始化为-1
for (size_t i = 0; i < 10; i++)
{
for (size_t j = 0; j < 10; j++)
{
tempArr[i][j] = -1;
}
}
//循环取出数组中每个数的个十百千..单个数字
//根据取出的个十百...的单个数字,将数组元素放在临时二维数组中去(临时数组
//的行是i值,列是个十百千..的单个数组)
int m = 0;
for (size_t i = 0; i < len; i++)
{
m = arr[i] / n % 10;
tempArr[i][m] = arr[i];
}
//将临时二维数组中的元素重新放回原来数组arr中
int index = 0;
for (size_t i = 0; i < 10; i++)
{
for (size_t j = 0; j < 10; j++)
{
if (tempArr[j][i] != -1) //需要注意的是从二维数组中去数据的时候是根据0列,1列,2列的顺序来取出的
{ //不能一行一行的取出(因为我上面放数据的时候是将分离的个十百..得数作为了二维数组的列了)
arr[index++] = tempArr[j][i];
}
}
}
}
}
1、快速排序:
//通过给元素找合适的位置来达到排序的一种方式
void Quik_Sort(int arr[],int low,int high)
{
int pos;
if (low < high)
{
pos = FindPos(arr, low, high);
Quik_Sort(arr, low, pos - 1);
Quik_Sort(arr, pos + 1, high);
}
}
int FindPos(int arr[], int low, int high)
{
int tempVal = arr[low];
while (low < high)
{
while (high>low && arr[high]>=tempVal)
{
high--;
}
arr[low] = arr[high];
while (low < high && arr[low] <= tempVal)
{
low++;
}
arr[high] = arr[low];
}
arr[low] = tempVal;
return low;
}
五、数组:
%s输出是以\0作为结束标志
字符串结束标志‘\0’
\0是占一个字节的
Sizeof(“I Love You”) 的出来的长度是11,是算上\0的
将小写字符串转换成大写:
头文件:#include <string.h>
strupr()用于将字符串中的字符转换为小写,其原型为:
char *strupr(char *str);
【参数说明】str为要转换的字符串。
【返回值】返回转换后的大写写字符串,其实就是将str返回。
Strupr(str);
将大写转换成小写:
Strlwr(str);
字符串比较函数:
Strcmp(str1,str2);
等则0 大则+ 小则-
连接字符串:
Strcat()
函数:
递归:
递归的两个条件
1、唯一的退出条件---------存在一个if语句
2、数学推导公式
作用域限定符 {}
当全局变量和局部变量一样的时候,编译器采用就近原则
图形库编程
使用graphics图形库插件进行使用C++图形化编程
不能创建.c工程,必须使用c++环境,也就是创建.cpp工程
Setbkcolor(RED);
然后刷新才可以显示设置好的背景颜色
cleardevice();
划线:
Setlinecolor(RED);//设置线的颜色,不需要刷新屏幕,如果不行,重新生成一下即可
Line(0,0,640,640);
画圆:
Circle(10,10,5);
画填充圆:
Setfillcolor(RED);//设置填充颜色,不需要刷新屏幕
Fillcircle(10,10,10);
画矩形:
Rectangle(10,10,20,20);
Fillrectangle(10,10,20,20);//画填充矩形
fill和solid的区别:
Fill是填充,solid是画的实线
设置线的样式:
Setlinstyle(PS_pash,3);
文字输出:
Settextstyle(20,30,”宋体”); 宽度,高度
Outtextxy(x,y,”输出字符串”);
将数字以字符串格式输出
Char str[20]=””;
Int a=30,b=45;
Sprintf(strt,”%d %d”,a,b);
Outtextxy(x,y,str);
贴图:
只支持bmp或者jpg格式的图片
1、不存储图片的贴法:
Loadimage(NULL,”./1.jpg”);
2 Image img;
Loadimage(&img,“./1.jpg”,600,480);
Putimage(0,0,&img);
得到图片的宽度高度
Img.getheight();
Img.getwidth();
图形库终极篇:
透明遮罩法:
先贴掩码,再贴背景(背景要是黑底)
掩码图-------------白底黑色 and方式 srcand
原图----------------黑底彩色 or方式 srcpaint
如果使用透明遮罩法之后图片显示是透明的,那么错误只有一个,就是掩码图片没有贴成功
putimage(200, 230, &oriImg[i],SRCPAINT);
只是执行上面的一句话就是透明效果的
指针:
所有指针所占用的字节都一样,是四个字节
因为一个内存单元就是四个字节,因为地址的值只能是整形类型
数组名绑定的就是一段内存
特殊指针:
NULL 就是(void*)0
现在使用nullptr
因为有时NULL和0区分不了
野指针:
没有指向的指针
Char *pstr=”I Love You”; //OK指向字符串的一段内存
Char *pstr1=’a’;//不行
栈内存:按照特定顺序进出的内存
堆内存:随意进出
数组名指针常量不能进行加减运算
内存四区:
栈:存放局部变量
堆:用户自己动手申请内存
数据:
代码:存放可执行代码二进制
为什么char *p=”Love”;可以,int *p=1;不可以???
原因:因为字符串就是相当于字符数组多一个\0,而int *p=1;类型是不一样呀
栈:内存从上往下是由小变大的
数组指针:
int Array[3][3]={1,2,3,4,5,6,7,8,9};
那么如何使用Array[3]一维数组,作为每个一维数组存放3个元素的表示呢?
如果要每个Array[i]存放三个元素,直接放三个肯定是不行的嘛,因为Array[i]的类型是int类型的只能存放整数的吗,那么如何让Array[i]存放三个元素呢,除非每个Arraay[i]都表示一个数组,那么表示出来就是 int *Array[i] 也就是int (*Atrray)[3]
如何使用指针来表示二维数组???
例如:
int Array[3][3]={1,2,3,4,5,6,7,8,9};
int (*Array)[3]
那么为题来了为什么要加()???
原因:因为 [] 的优先级高于 * 如果首先 int Array[3];这就是一个数组,然后*再和数组结合 int *Array[3] ; 很明显这就是 指针数组了嘛!!!
因为一维数组int a[3] ,使用指针来表示就是 int *a; 加括号就是为了让int (*Array)[3];
从左往右编译,就像 int a[3][3];编译器编译的时候就是从左往右编译的
int a[3][4][5];
int *(*(*(P+i)+j)+k)
int a[3][4];
int *(*p)[4]
int *(*(p+i)+j)
int a[3]={1,2,3};
为什么 a 和 &a[0] 和&a,输出的值是一样的????
原因其实很简单,a和&a[0]肯定是一样的不用解释,那么&a不是取得a的地址吗,怎么还会一样呢?这种情况可以根据二维数组来理解,&a的数据类型就是 int (*)[3] 的类型,是个数组指针,那么对于二维数组 int b[3][4]; 中b[0] b[1] b[2] 的类型都是int (*)[4] 的类型,都是数组指针,那么 b 和&b 和 &b[0] 和&b[0][0] 是不是都是一样的,再来比较一维数组中 &a和 a 这时
&a 不就相当于二维数组的b
A不就相当于二维数组的b[0]/b[1]/b[2] 吗
所以&a 和a 的值就是一样的
System 命令
关机:
Shutdown -s (等待30s或者60s)
取消关机
Shutdown -a
定时关机:
Shutdown -s -t 60 (60秒之后关机)
在某个时间点关机:
At 21:00 shutdown -s (在9点关机有些电脑不能使用)
Windows+r cmd 输入color/?,就可以查看控制台颜色搭配
Microsoft Windows [版本 10.0.14393]
(c) 2016 Microsoft Corporation。保留所有权利。
C:\Users\zhangweijie>color
C:\Users\zhangweijie>color/?
设置默认的控制台前景和背景颜色。
COLOR [attr]
attr 指定控制台输出的颜色属性。
颜色属性由两个十六进制数字指定 -- 第一个
对应于背景,第二个对应于前景(文字)。每个数字
可以为以下任何值:
0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 浅绿色 B = 淡浅绿色
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色
如果没有给定任何参数,此命令会将颜色还原到 CMD.EXE 启动时
的颜色。
设置控制台颜色:
System(color 01);
播放音乐:
#include<mmsystem.h>
#pragma comment (lib,”winmm.lib”)
MP3格式:
打开音乐:
Mcisendstring(“open ./111.mp3 alias zhang”,0,0,0);
播放音乐:
Mcisendstring(“play 111 repeat”,0,0,0);
也可以不给音乐起别名直接play 音乐路径音乐名.mp3 repeat
例如:
Mcisendstring(“play ./bgMusic.mp3 repeat ”,0,0,0);
暂停音乐:
Mcisendstring(“pause 111”,0,0,0);
Stop
关闭音乐:
Close
Wav格式音乐:
PlaySound函数的声明为:
BOOL PlaySound(LPCSTR pszSound, HMODULE hmod,DWORD fdwSound);
参数fdwSound是标志的组合,如下表所示。若成功则函数返回TRUE,否则返回FALSE。
PlaySound(NULL,NULL,NULL);停止播放。
Playsound(“./音乐名.wav”,NULL, SND_FILENAME | SND_LOOP|SND_ASYNC);
Mcisenstring 可以播放MP3和wav格式的音乐,但是无法使用资源文件
Playsound 只可以播放wav格式的音乐,可以使用资源文件
播放资源中的wav音乐:
PlaySound(MAKEINTRESOURCE(103), NULL,SND_RESOURCE);
Playsound(MAKEINTRESOURCE(103),NULL,SND_ASYNC|SND_LOOP|SND_RESOURCE);
SND_ASYNC 异步播放 立刻返回
如果要想循环播放则必须与是异步播放的方式
SND_SYNC 同步播放,播放完后才返回
//贴图的第一种方式,不需要声明IMAGE 变量,直接在窗口中加载图片
//缺点:不能指定位置
//loadimage(NULL, L"./111.jpg",600,480);
//使用资源文件中的资源:不需要将资源和exe程序放在一起,就可以在其他电脑上直接使用
// IDR_JPG1 jpg "111.jpg"
IMAGE img;
loadimage(&img, "jpg", MAKEINTRESOURCE(1),600,480);
动态内存分配:
#include<malloc.h>
int *malloc(unsigned int size)--------->申请堆内存
free()------------------->释放内存
int *array;
Array=(int *)malloc(sizeof(int)*num);//申请可以存放num个数字的int类型的内存大小
int *Calloc(count,size);
和malloc的区别可以对数据进行初始化
动态申请二维数组
int **p=(int **)malloc(sizeof(int *)* 4);//p是一个数组指针
for(int i=0;i<4;i++)
{
P[i]=(int*)malloc(sizeof(int)*4);//p[i]是一个指针数组
}
因为p指向的是一个数组,所以p是数组指针
因为p[i]存放的是多个指针,所以p[i]是一个指针数组
可以动态申请二维不规则数组
指针补充:
存放地址的变量 简单商户就是变量,复杂说包括(数组 结构体 函数)
存放的是什么的地址,就是什么样的指针
存放的是数组的地址就是数组指针
存放的是函数的地址就是函数指针
存放的是结构体变量的地址就是结构体指针
指针的输出,一般不会有指针的输入,因为地址是不知道的呀
%p专门用来输出地址(十六进制)
指针与指针相加没有意义
指针相减可以计算长度 (是两个指针之间的元素的个数,单位并不是字节)
Int pArr[10]={0,1,2,3,4,5,6,7,8,9};
假如 p1指向 第一个 p2指向 第十个
那么p2-p1得到的结果就是 9
一维数组等价 一维指针
二维数组等价 数组指针
三维数组 二维数组的指针
数组指针指向数组的长度
Typedef int a;
Typedef int(*ZHANG)[10];
ZHANG p;//p是一个二维数组
Int (*p)[10]; p++移动一个数组的大小
Int **p ;移动那个一个指针的大小
数组名是不占内存的
Int a;========》计算机是直接操作地址的
Char *pArr=”hello”; 相当于 const char *pArr=”hello”;
pArr在栈区,hello在常量区
*pArr=’0’ //错误
Scanf(“%s”,pArr);
结构体:
Struct student
{
Char name[5];
Int age;
Int num;
};
结构体在没有初始化之前就是占用内存的,并且结构体成员的内存是连续的
Sizeof(struct student);得到的值是 4+4+4+4=16
在32位计算机操作系统上一个内存单元是4个字节(就是一个地址所占用的内存)
16是 2
64是 8
对齐说白就是内存的填充
联合体 union
Union test
{
Double a;
Int b;
};
联合体是所有成员公用最大成员所占的那一个内存
只能对一个成员操作,如果对多个成员操作了,后面的会覆盖前面的操作的,操作的都是同一个内存
枚举类型:
Enum Myenum
{
UP=’w’,
Down=’S’,
LEFT=’A’,
RIGHT=’D’
};
枚举的值都是整形类型的常量默认从 0开始
如果是初始化为了字符的化,是转成了ASCII的值
动态链表:
为什么结构体中不可以定义本身结构体类型的成员,但是可以定义本身类型的指针?
这需要从结构体的内存大小来说,因为如果定义一个结构体类型的成员的话,结构体的大小是不确定的,但是,指针的大小就是确定的,所以定义指针就是可以的。
栈:就是头插法
创建表头
创建结点
头插法插入结点
尾插法插入结点
判断链表是否为空
在指定位置插入结点
头删除
尾删除
指定位置删除
有表头的链表
所谓表头就是一个头结点,是在第一个结点之前的结点,其结点的指针域存放第一个结点的地址,有了头结点可以方便对链表的操作
头结点的作用是使所有链表(包括空表)的头指针非空,并使对单链表的插入、删除操作不需要区分是否为空表或是否在第一个位置进行,从而与其他位置的插入、删除操作一致。
头指针与头结点的异同点:
头结点:头结点是为了操作的同意和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度),有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了
头结点不一定是链表的必须元素
头指针:
头指针是指向链表第一个个元素结点的指针,若链表有头结点,则是指向头结点的指针。
头指针具有标识作用,所以常用头指针冠以链表的名字
无论链表是否为空,头指针均不为空,头指针是链表的必要元素
如何理解上面这句话:头指针不论是单独的一个指针还是在头结点中的指针域的指针,反正是必须要有的,所谓的头指针不为空也是一个意思头指针存在。头指针的指向为空和头指针为空并不是同一个概念
链表可以没有头结点,但是不能没有头指针如何理解?
链表没有头结点,只有一个头指针是OK的,是可以通过头指针遍历整个链表的
其实只要有头结点就有头指针了,因为头结点的指针域就相当于头指针了
线性表分为:顺序存储结构----------数组
链式存储结构----------链表
非线性也就是树了
文件操作:
Fread和fwrite需要注意的是以什么方式写进去的就要以什么方式读出来
Fwrite(&mystudent,sizeof(struct Student),1,fp);
预处理:
宏函数中参数尽量用小括号括起来,因为在#define后面的所有的变量都是直接替换的
#define SWAP(a,b) (a=a+b,b=a-b,a=a-b)
#define RESULT(a,b) (a*b+b)
Int main()
{
RESULT(3,4+3);//得出的结果是3*4+3+3=18 并不是28
}
#if 条件
#elif 条件
#else
#endif
#ifdef
#else
#endif
#ifndef
#else
#endif
取消定义
#define MIN 1
Printf(“%d”,MIN);
#undef MIN//删除宏定义MIN
#line 100//表示从下一行开始就是100行开始的
用法:#line 100
如何打印行号 printf(“%d”,__LINE__);//注意是两个下划线
#pragma message(“hello world”)
__DATE__打印项目创建日期
__TIME__打印项目创建时间
__FILE__打印项目路径
Static 内部
Extern 外部 告诉编译器该变量是在另一个文件中定义的
多文件操作注意事项:
一个文件中使用的全局变量最好定义在.cpp文件中,如果定义在.h文件中,那么另一个文件包含一次该头文件,就会将全局变量编译一次,如果有两个或者多个文件包含了同一个头文件,那么就会出现重定义现象,解决办法就是将头文件中的该变量在.cpp文件中定义,外部文件有要使用该变量的使用extern关键字说明一下,该变量在其他文件中有定义,这样就不会报错了
尽量不要连个头文件互相包含,不然你如果在一个头文件中定义了变量,那么就会出现重定义的错误
栈和队列:
栈stack:
FILO 先进后出
特性:
栈顶标记:top
栈操作:
Void Push() //进栈
Void pop() //出栈
Typename top() //获取栈顶元素
Bool empty()//栈是否为空
.~int();//释放int内存
栈使用top
队列使用front rear
双向循环链表:
插入的时候要先查找位置,然后在创建结点,因为如果位置不存在,就没必要创建结点了