1.基础:
(1)system函数:支配电脑干活
函数调用system:运行window命令
例:system(“ifconfig”);
system("pause");//作用:等待用户输入,造成程序在输入之前不会结束
(2)提高程序效率的方法:
1.少用全局变量
2.少用if
3.少定义函数
(3)getchar()函数用来获取一个字符
使用:吸收回车,回车也是一个字符
(4)putchar()函数用来输出一个字符
例如:putchar('\n');
(5)不同类型的数据运算时,比如两个整数相除,必须将除数或者被除数强制转换成小数,否则小数点后面的数据将被忽略
int a;
int b;
float ret;
ret = (float)a/b;
(6)在windows啊哈c中用4个字节表示地址,linux 64位中用8个字节表示地址
(7)一般在main()里面(包括定义的函数里面)是局部变量
main外面是全局变量
少用全局变量
2.选择/判断语句:
(1)死循环:
while(1);
for(;;);
(2)一些选择语句的使用:
if(判断){
......
}else{
.....}
if(判断){
......
}else if(判断){
......
}else if(判断){
......
}else{
......
}
switch(){
case _ :
case _ ://(执行结果一样)
执行;
break;
case _ :
执行;
break;
default:
执行;
break;
}
(3)一些循环语句的使用:
while(1){
}
for(初始条件;当不满足此情况不执行循环体;让条件变化)
例:for(i = 0;i < 3;i++){
}
(4)while和do…while的区别:
while
do{...}
while(1);
//后者比前者至少多运行一次
3.函数(函数可以多级调用)
函数调用中,传参就是一个赋值的过程!!!实际参数的值给形式参数
(1)如何定义一个函数:
1.返回值
2.形式参数(局部变量)
3.函数名
4.函数体(代码块)
(2)如何调用一个函数
1.函数名(实际参数);
2.函数名();
(3)一般函数定义几种情况:
1.无返回值无参数
2.无返回值有参数
3.有返回值有参数
4.有返回值有多个同类型参数
5.有返回值有多个参数,参数类型不同
6.根据需求,各种组合都行
4.数组(地址连续):
(1)数组几个重要特征:
1.数组是数据的集合
2.数组的数据是同类型的
3.数组的地址是连续的
(2)数组的几种定义方式
int array[100];没有初始化的数组,仅仅申请了100个整型数的内存空间(最好进行初始化:int array[100] = {0};)
int array2[3] = {1,2,3};有初始化的数组,完整初始化,该数组申请了三个整型数的内存空间,并赋值三个数1,2,3
int array3[100] = {1,2,3};有初始化的数组,不完整初始化,该数组申请了100个整形数的内存空间,但只赋值三个数1,2,3放在数组的前3个位置
(3)数组的访问和赋值:
scanf("%d",&array[i]);
printf("%d",array[i]);
(4)数组的遍历(for循环):
int i;
for(i = 0;i < sizeof(array)/sizeof(array[0]);i++){
printf(" %d ", array[i]);
}
(5)数组与函数(数组关心的是数组的首地址(数组名:array;)(第一个元素的首地址:&array[0];))
形式参数中,中括号中的数组的大小是无效的,中括号仅仅用来表示形式参数的一个地址
函数定义void arrayPrint(int data[],int cnt);
//地址 //个数
函数调用:arrayPrintf(array,sizeof(array)/sizeof(a[0]);
arrayPrintf(&array[0],sizeof(array)/sizeof(a[0]);
//一样的(数组的首地址的两种表示形式)
5.指针(地址):
(1)定义和赋值:
- :只有在定义一个指针变量的时候,才是指针的标识符其余为:取内容
int *p; 或者 int *p = &a; (错误写法:int *p; *p = &a;)
p = &a;
(2)指针与数组:
int *parray;
parray = &array[0];或者parray = array;
两种遍历方式:printf("%d",*parray); parray++;(注意指针的位置,不要超出数组,否则会看到乱码)
printf("%d",array[i]);
(3)指针数组与数组指针
1.指针数组:指针的数组(多个指针)://偏移值:偏移一位
int a = 1;
int b = 2;
int c = 3;
int *P[3] = {&a,&b,&c};
2.数组指针(一个指针)//偏移值:整个数组的大小
int a[3] = {1,2,3};
int (*p)[3];
p = &a;
(4)使用指针的原因:
原因1:给内存的指定位置赋值
int *p = (int *)0x0060ff00;
*p = 10;
printf("在内存的%p位置,存放值是%d\n",p,*p);
原因2:指针操作的是本身(如果操作的是内容本身,main里面的值不变)
例如:void jiajiaA(int *p){
*p = *p + 1;
printf("a = %d",*p);
}
int main(){
int a = 10;
jiajiaA(&a);
printf("a = %d);
return 0;
}
(5)函数指针(存放的是函数的地址)
1.定义
void (*p)();
2.赋值
p = 函数名(函数名就是地址,跟数组一样,数组名就是地址)
3.如何调用
p(); 直接通过指针名字加();
(*p)(); 取内容(*指针名字)();
(6)无类型指针
定义:int *parray = (int *)malloc (n*sizeof(int));
数组
int *p; //野指针
int *p = NULL;//不是野指针
(7)内存泄漏
现象:程序刚跑起来很好,跑几个小时,几天程序奔溃
原因:malloc申请的空间,程序不会主动释放,linux中的话,程序结束后,系统会回收这个空间
如何避免:1.注意循环中有没有一直申请空间
2.及时合理的释放
free (p);-----变成野指针
p = NULL;------避免变成野指针
6.字符串(字符数组):
(1)定义
1.char str[5] = "abcde";
2.char str[] = "abcdefgh";
数组元素不写,会根据真实大小来默认分配(整形数组也是)
3.char *pstr = "abcdefghijk";
(指针操作不当,易造成段错误)
(2)字符串的存储方式以及如何计算字符串的大小
存储方式:字符串在内存中,除了有效字符以外,还会自动在后面补一个"\0",作为字符串的结束标识
计算方式:不能用sizeof来计算字符串中有效字符的个数!!!
应该要用strlen,它在计算字符串大小的时候,遇到"\0"后,就结束计数
(3)字符串几种常用的API
头文件:<string.h>(具体使用可以使用的时候百度)
对于一个数组指针要进行多次复制,最好使用memset进行初始化'\0'
1.输出字符串:puts(); printf("%s",pstr);
2.获取字符串:gets(); scanf("%s",p);//内存必须合法
3.计算长度:strlen();
4.初始化:memset(); // memset(cmd,'\0',sizeof(cmd));
5.拷贝:strcpy(); strnpy();
6.拼接:strcat();
7.比较:strcmp();
8.查找子字符串:strchr();
9.查找子串:strstr();
(接下来几个在window环境下,要定义成数组的形态,否则奔溃,Linux下是可以的)
10.转为小写字符串:strlwr();
11.转为大写字符串:strupr();
12字符串分割:strtok();
(4)野指针,避免段错误‘’
char *pstr;//野指针,造成非法内存空间,会出现段错误(具体现象:cmd窗口闪退)
如何避免:开辟空间(char pstr[128] = {'\0');)
char *pstr = NULL;
pstr = (char *)malloc(128);//malloc一旦使用必须注意内存泄漏
memset(pstr,'\0',128);
7.结构体(类型不同的一组数的集合):
(1)定义、使用和访问
定义:
struct student{
char *name;(正确写法:strcpy(stu.name,"张三");)(错误做法:stu.name = "张三";)
(char *name:使用的时候一定要开辟空间)
int score;
};
使用:
struct student stu = {};
访问:
stu.name;
(2)结构体数组、结构体指针数组
结构体数组:struct student stus[10];
结构体指针数组:
1.struct student stus[5];
struct studnet *p = stus;
2.struct student *p = (struct studnet*)malloc(len*sizeof(struct student);
(3)结构体指针
1.如果使用结构体指针,就不能用点运算符访问结构体中的变量,要用->
2.指针要注意是否为野指针或者NULL,要进行初始化,不然会发生段错误
例:struct student *p;//野指针(初始化)
p = (struct student *)malloc(sizeof(struct student);
3.一旦使用malloc,为了避免内存泄漏:及时合理的释放free(p);
(4)结构体函数指针
struct student *findMaxStu(){
}
(5)面试宝典之结构体的大小如何计算
1.结构体成员的偏移量必须是成员大小的整数倍
2.结构体大小必须是所有成员(数组、结构体除外)大小的整数倍
//结构体中的结构体,如果只是申明,直接不算!!!要定义一个结构体变量才算
对齐方式很浪费空间,确实。。。可是按照计算机的访问规则,这种对齐方式提升了效率
一些注意事项:
联合体的大小就是成员中最大类型的大小
#pragma pack(4);
如果成员的大小超过了pack要求的,就按pack来对齐,如果最大成员大小没有超过pack,结构体的总大小,就按最大成员大小来对齐
(6)typeof为c语言的关键字
作用:为一种数据类型定义一个新名字(这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等))
例:typedef unsigned char u_int8;//8位
typedef unsigned short int u_int16;//16位
typedef unsigned int u_int32;//32位
结构体:typedef struct studnet{
int score;
char *name;
}STU;
8.链表(链表的每一项都是结构体)----灵活:
(1)静态创建:
struct Test {
int data
struct Test *next;
};
struct Test t1 = {1,NULL};
struct Test t2 = {2,NULL};
struct Test t3 = {3,NULL};
t1.next = &t2;
t2.next = &t3;
printf("use t1 to print three nums\n");
printf("%d %d %d",t1.data,t1.next->data,t1.next->next->data);
(2)链表的遍历:
void printLink(struct Test *head);
{
struct Test *point;
point = head;
while(point != NULL){
printf("%d",point->data);
point = point->next;
}
putchar('\n');
}
(3)链表的插入—插入新节点
1.节点的后方
void insertBehind(struct Test *head,int data,struct Test *new){
struct Test *point;
point = head;
while(point != NULL){
if(point->data == data){
new->next = point->next;
point->next = new;
}
point = point++;
}
}
2.节点的前方
两种情况:
//第一个节点目标节点(链头)
//不是头
struct Test* insertHand(struct Test *head,int data,struct Test *new){
struct Test *point;
point = head;
if(point->data = data){
new->next = head;
return new;
}
while(point->next != NULL){
if(point->next->data == data){
new->next = point->next;
point->next = new;
printf("已经找到,插入成功\n");
return head;
}
point = point->next;
}
printf("没有找到,插入失败\n");
return head;
}
(4)链表的删除
两种情况://第一个节点(头)//后面的节点
struct Test *deleteNode(struct Test *head,int data){
struct Test *point;
point = head;
if (point->data == data){
point = point->next;//(如果使用malloc,记得free();,避免内存泄露)
return head;
}
while(p->next != NULL){
if(p->next->data ==data){
p->next = p->next->next;
return head;
}
point = point->next;
}
return head;
}
(5)链表的动态创建—头插法
struct Test *insertFromHead(struct Test *head,struct Test *new){
if(head == NULL){
head = new;
}else{
new->next = head;
head = new;
}
return head;
}
struct Test *createLink(struct Test *head){
struct Test *new;
while(1){
new = (struct Test *)malloc(sizeof(struct student));
printf("input your new node data:\n");
scanf("%d",&(new->data));
if(new->data == 0){
printf("0 quit\n");
free(new);
return head;
}
head = insertFromHead(head,new);
}
}
(5)链表的动态创建—尾插法
struct Test insertFromBehind(struct Test *head,struct Test *new){
struct Test *point = head;
if(point == NULL){
head = new;
return head;
}
while(point->next != NULL){
point = point ->next
}
point->next = new;
return head;
}
struct Test *createLink(struct Test *head){
struct Test *new;
while(1){
new = (struct Test *)malloc(sizeof(struct student));
printf("input your new node data:\n");
scanf("%d",&(new->data));
if(new->data == 0){
printf("0 quit\n");
free(new);
return head;
}
head = insertFromBehind(head,new);
}
}