变量的存储类别
存储类别小结图
作用域角度
全局变量
在所有函数外部定义的变量叫全局变量
全局变量的使用范围:从定义位置开始到整个程序结束
局部变量
在一个函数内部定义的变量或者函数的形参 都称为局部变量
void f(int i)
{
int j=20;
}
i和j都属于局部变量
局部变量使用范围:只能在本函数内部使用
注意的问题:
全局变量和局部变量命名冲突的问题,在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用
预处理命令
宏定义和调用(带参数的宏,不带参数的宏)
# define 标识符 字符串# define 宏名 宏体
特点:源位置替换,一改全改,可嵌套定义
无参
# include <stdio.h>
# define PI 3.14
# define M 2+3
void main()
{
int r = 1;
2 * PI * r;
PI * r * r;
printf("%d\n",M*M);//结果显示11
}
# include <stdio.h>
# define PI 3.14
# define M (2+3)
void main()
{
int r = 1;
2 * PI * r;
PI * r * r;
printf("%d\n",M*M);//结果显示25
}
带参
# include <stdio.h>
# define MAX(a,b) ((a) > (b)? (a):(b))
void main()
{
int i = 3,j = 5;
printf("%d\n",MAX(i,j));
}
“文件包含” 处理
# include <stdio.h>目的引用头文件的标准输入输出函数
预处理:处理程序中所有以# 开头的行,如# include ,# define, # if ,#else ,#ifdef ,# ifndef
结构体
为了表示一些复杂的事物,而基本的数据类型无法满足实际要求,把一些基本的数据类型组合在一起形成一个新的复杂的数据类型
结构体类型的声明定义及引用
结构体类型的声明
struct 结构体名
{
数据类型1,成员名1;
数据类型2,成员名2;
……
};
结构体类型的定义初始化及引用
//无头,无头结构体必须在结构体成员描述后将变量一次性定义好
//有头不作要求
3种方式,推荐使用第一种方式
//第一种方式
struct 结构体名
{
成员名表列
};
//第二种方式
struct 结构体名
{
成员名表列
}变量名表列;
//第三种方式
struct
{
成员名表列
}变量名表列;
定义初始化及引用举例
# include <stdio.h>
struct student
{
int age;
float score;
char sex;
};
void main()
{
struct student st={80,66.6,'F'};//定义的同时赋值初始化
struct student st2;//先定义,然后引用变量名.成员名
st2.age = 80;
st2.score = 88;
st2.sex = 'A';
/*struct student *pst = &st;//指针变量名->成员名
pst->age=80;
*/
printf("%d %f %c\n",st.age,st.score,st.sex);
printf("%d %f %c\n",st2.age,st2.score,st2.sex);
}
*指针变量名->成员名,在计算机内部转化为(指针变量名).成员名的方式来执行,所以说这两种方式是等价的
结构体变量和指向结构体的指针作函数参数
# include <stdio.h>
# include <string.h>
struct student
{
int age;
char name [100];
char sex;
};
Inputstudent (struct student * pst);
Outputstudent (struct student * pst);
void main()
{
struct student st;
Inputstudent (&st);//对结构体变量输入,必须发送st的地址
Outputstudent(&st);//对结构体变量输出,可以发送st的地址也可以发送st的内容,为了减少内存消耗,推荐使用地址发送
}
Inputstudent (struct student * pst)
{
(*pst).age = 10;
strcpy(pst->name,"张三");
pst->sex = 'F';
}
Outputstudent (struct student * pst)
{
printf("%d %s %c",pst->age,pst->name,pst->sex);
}
共用体
共用体类型的声明定义及引用
共用体类型的声明
union 共用体名
{
数据类型1,成员名1;
数据类型2,成员名2;
……
};
结构体类型的定义初始化及引用
//无头,无头结构体必须在结构体成员描述后将变量一次性定义好
通过变量名:不能一次性引用到所有的成员,引用方式:变量名.成员名或指针->成员名
占内存大小
所有成员共用同一块空间,同一个时刻只有一个成员生效,共用体大小由成员中中占位最大的成员决定
共用体与指针,共用体参与传参
枚举
枚举的定义:把一件事物所有可能的值一一列举出来
枚举的应用
# include<stdio.h>
enum weekday
{
MonDay, TuesDay, Wednesday, ThursDay, FriDay, SaturDay, SunDay//不作说明,本质上是0——6的数字,但实际不能这样写
};
void f(enum weekday i)//本函数的目的是期望接收0——6的数字,将形参i定义为枚举类型
{
switch (i)
{
case 0:
printf("MonDay!\n");
break;
case 1:
printf("TuesDay!\n");
break;
case 3:
printf("WednesDay!\n");
break;
case 4:
printf("ThursDay!\n");
break;
case 5:
printf("FriDay!\n");
break;
case 6:
printf("SaturDay!\n");
break;
case 7:
printf("SunDay!\n");
break;
}
}
int main(void)//实质上是0——6,但是不能输入,只能输入FriDay
{
f(FriDay);
return 0;
}
动态内存分配【重点难点】
传统数组的缺点:
1.数组长度必须事先制定,且只能是常数,不能是变量。例子: int a[5];//OK int len = 5; int a[len]//eror
2.传统形式定义的数组,该数组的内存程序员无法手动释放在一个函数运行期间,系统为该函数中数组中所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放
3.数组的长度一旦定义,其长度就不能在更改;
数组的长度不能在函数运行的过程中动态的扩充或缩小
4.A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用
动态分配内存的举例----动态数组的构造
malloc函数的使用简单介绍
# include <stdio.h>
# include <malloc.h>
int main(void)
{
int i = 5;//分配了4个字节,静态分配
int * p = (int *)malloc(4);//11行
/*
1.要使用malloc函数,必须添加malloc.h这个文件
2.malloc函数只有一个形参,并且形参是整型
3.4表示请求系统为本程序分配4个字节
4.malloc函数只能返回第一个字节的地址
5.12行分配了8个字节,p变量占个字节,p所指向的内存也占4个字节
6.p本身所占的内存是静态分配的,p所指向的内存是动态分配
*/
*p = 5;//* p代表的就是一个int变量,只不过* p这个整形变量的内存分配方式和11行的内存分配方式不同
free(p);//free(p)表示把p所指向的内存给释放掉,p本身的内存是静态的,不能右程序员手动释放,p本身的内存只能在变量所在的函数 运行终止时由系统自动释放的
printf("同志们好!\n");
return 0;
}
# include<stdio.h>
# include<malloc.h>
void f(int * q)
{
* q = 200;
}
int main()
{
int * p = (int *)malloc(sizeof(int));
*p = 10;
printf("%d\n",*p);
f(p);
printf("%d\n",*p);
}
动态数组的构造
# include<stdio.h>
# include<malloc.h>
void main()
{
int len;
int * pArr;
int i;
//动态的构造一维数组
printf("请输入你要存放的元素的个数");
scanf("%d", &len);
pArr = (int *)malloc(4 * len);//本行动态的构造了一个一维数组,该一维数组的长度是len, 该数组名是pArr,数组元素类型是int 。类似于int pArr[i];
//对一维数组进行操作,如,对动态一维数组进行赋值
for(i=0;i<len;i++)
scanf("%d",&pArr[i]);
//对位一维数组进行输出
printf("一维数组的内容是\n");
for(i=0;i<len;i++)
printf("%d\n",pArr[i]);
free(pArr);//释放掉动态分配的数组
return 0;
}
静态内存和动态内存
静态内存
静态内存不能跨函数使用,由系统自动分配,自动释放,在栈中分配
# include<stdio.h>
void f(int ** q)//q是个指针变量,无论q是什么类型的指针变量,都只占4个字节
{
int i = 5;
//*q等价于p,q和**q都不等价于p
//*q = i;//error 因为*q等价于p=i;这样写是错误的
*q=&i;//p=&i;
}
void main()
{
int *p;
f(&p);
printf("%d\n",*p);//本句语句语法没有问题,但逻辑上有问题
return 0;
}
动态内存
动态内存能跨函数使用,可由程序员分配,手动释放,在堆中分配
# include<stdio.h>
void f(int ** q)
{
*q = (int *)malloc(sizeof(int));//sizeof(数据类型)返回值是该数据类型所占的字节
//等价于 p = (int *)malloc(sizeof(int));
//q=5;//error
//*q=5;//p=5;//error
**q=5;//*p=5;
}
void main()
{
int *p;
f(&p);
printf("%d\n",*p);
return 0;
}
指针与链表
位运算
1.&——按位与 0&0=0;0&1=0;1&0=0;1&1=1
2.|——按位或 0|0=0; 0|1=1; 1|0=1; 1|1=1
3.^——异或 0 ^0=0; 0 ^1=1; 1 ^0=0; 1 ^1=0;
4.~——取反 0变成1;1变成0
5.<<——左移运算符 (放大数据) 左移n位,放大2^n倍
6. >>——右移运算符 (缩小数据) 右移n位,缩小2^n倍
文件
意义:数据可实现永久存放I/O操作:input ,output
文件类型指针
typedef struct
{
short level;/*缓冲区“满”或“空”的程度*/
unsigned flags;/*文件状态标志*/
char fd;/*文件描述符*/
unsigned char hold;/*如缓冲区不读取字符*/
short bsize;/*缓冲区的大小*/
unsigned char *buffer;/*数据缓冲区的位置*/
unsigned ar *curp;/*指针,当前的指向*/
unsigned istemp;/*临时文件,指示器*/
short token;/*用于有效性检查*/
}FILE;
FILE *fp;//f是一个指向FILE类型结构体变量的指针变量
文件的打开与关闭
文件的打开
FILE*fopen(const char filename;const char * mode)
filename :要打开的文件
mode:打开方式
FILE:成功,返回非空指针;失败,返回空指针
mode 使用文件方式表
文件的关闭
int fclose (FILE*fp)
fp:成功打开文件的标识,目前要选择关闭的文件
int:0成功;1失败
# include <stdio.h>
void main()
{
FILE *fp;
fp=fopen("myfile111.text","w");
if(fp == NULL)
{
printf("fopen()error.\n");
return ;
}
printf("OK\n");
fclose(fp);
}
文件的读写
fputc函数和fgets函数(puts函数和gets函数)
fgets函数
调用形式:ch=fgets(fp); fp为文件型指针变量,ch 为字符变量
fputs函数
调用形式:fputs(ch,fp); ch是要输出的字符 , fp是文件指针变量
作用:将字符(ch的值)输出到fp所指向的文件中去 成功输出,失败输出EOF
fread 函数和fwrite 函数
fread(buffer,size,count,fp)
fwrite(buffer,size,count,fp)
buffer:是一个指针。对于fread来说,是读入数据的存放地址;对于fwrite来说,是输出数据的地址(起始地址)
size:要读写的字节数
count:要进行读写多少个sizez字节的数据项
fp:文件型指针
fprintf函数和fscanf函数
fprintf(文件指针,格式字符串,输出表列)
fscanf(文件指针,格式字符串,输入表列)
其他读写函数
1.puts和gets函数(读写一个字)
2.fputs和fgets函数(从指定文件读入一个字符串)
文件的定位
rewind函数
作用:使位置指针重新返回文件的开头,此函数没有返回值
fseek函数和随机读写
fseek(文件类型指针,位移量,起始点)