数组
用一段连续空间 存放相同类型的变量 这样的容器(结构)叫数组。
数组的下标是从0开始。
假如数组有n个元素:
下标范围:0~n-1
元素范围:arr[0]~arr[n-1]
一维数组
定义数组的步骤
数组名 和 [] 表示数组
将数组的个数 放入[]里面
用元素的类型 定义一个变量
从上 往下 替换。
定义一个数组 有5个元素 每个元素为int: int a[5],数组名a,元素个数是5,元素类型为int
定义一个数组 有5个元素 每个元素为int * :int *a[5]
定义一个数组 有5个元素 每个元素为数组,该数组有10个元素每个元素为int : int a[5][10]
定义一个数组 有5个元素 每个元素为函数的入口地址,该函数有两个int型形参,int返回值类型
a[5]--*a[5]--(*a[5])(int,int)--int (*a[5])(int,int)
一维数组的初始化
全部元素 初始化
如果数组的全部元素 都初始化 可以省略[]的数值
如果省略了[]里面数值 数组的元素个数 就由初始化的元素个数确定
部分元素 初始化:未被初始化的部分 自动补0,按顺序初始化。
int a[5]={0};//将第0个元素初始化为0 其他未被初始化自动补0
int a[5]={1,2,3,4,5}//全部初始化
int a[5]={1,2,3,}部分初始化
一维数值数组的元素操作
#include <iostream>
#include<bitset>
using namespace std;
int main()
{
int a[5]={0};
int n=sizeof(a)/sizeof(a[0]); //数组总大小/数组元素大小=元素个数
int i=0;
for(i=0;i<n;i++) //从键盘输入元素的值
{
cout<<"给a["<<i<<"]赋值"<<endl;
cin>>a[i];
}
for(i=0;i<n;i++) //对一维数组进行遍历
{
cout<<a[i]<<"\t";
}
cout<<endl;
return 0;
}
二维数值数组
a[3][4]
3:3行,0,1,2
4:4列,0,1,2,3
二维数值数组的初始化
分段初始化
//完全初始化
int arr[3][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };
//如果完全初始化 只能省略行数,列数不可省略
int arr[][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };
//部分初始化
int arr[3][4]={ {1,2}, {5,6}, {9,10,11} };
连续初始化
/完全初始化,arr[3][4],12个元素挨个初始化
int arr[3][4]={ 1,2,3,4, 5,6,7,8, 9,10,11,12};
//如果完全初始化 只能省略行数,列数不可省略
int arr[][4]={1,2,3,4, 5,6,7,8, 9,10,11,12};
//部分初始化
int arr[3][4]={ 1,2, 5,6, 9,10,11};
二维数值数组的元素操作
#include <iostream>
#include<bitset>
using namespace std;
int main()
{
int a[2][3]={0};
int row=sizeof(a)/sizeof(a[0]);//行数
int col=sizeof(a[0])/sizeof(a[0][0]);//列数
int i=0,j=0;
for(i=0;i<row;i++) //赋值
{
for (j=0;j<col;j++)
{
cout<<"给arr["<<i<<"]["<<j<<"]赋值"<<endl;
cin>>a[i][j];
}
}
cout<<"遍历元素"<<endl;
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
cout<<a[i][j]<<" ";
}
}
cout<<endl;
return 0;
}
求每一行的平均数
#include <iostream>
#include<bitset>
using namespace std;
int main()
{
int a[5][4]={
{56,75,78,89},
{89,98,76,67},
{88,99,77,66},
{67,78,89,90},
{98,97,96,95}
};
int row=sizeof(a)/sizeof(a[0]);//行数
int col=sizeof(a[0])/sizeof(a[0][0]);//列数
float scoreAvg[5]={0.0f}; //定义一个一维数组,平均数为float类型
int i=0,j=0;
for(i=0;i<row;i++)
{
float sum=0;
for(j=0;j<col;j++)
{
sum=sum+a[i][j];
}
scoreAvg[i]=sum/col;//sum是float型,与col int型运算结果是float型
}
for (i=0;i<row;i++) //遍历scoreAvg数组
{
cout<<scoreAvg[i]<<endl;
}
return 0;
}
一维字符数组初始化
逐个元素初始化
char arr[5]={'h','e','l','l','o'};//''描述的是字符,这里有5个字节
以字符串的方式 初始化 一维字符数组
"“描述的是字符串, 比如字符串"hello”, 编译器会自动在字符串的末尾 添加’\0’字符 作为字符串的结束标
记
char arr[6]="hello";//""描述的是字符串, 编译器会自动在字符串的末尾 添加'\0'字符 作为字符串的结束标记,这里有5+1个字节
一维字符数组的遍历
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char a[32]={"\0"};
cout<<"输入字符串"<<endl;
/*cin获取字符串 遇到空格或回车 结束输入
*cin.getline获取带空格的 字符串*/
cin.getline(a,sizeof(a));
int i=0;
for(i=0;i<sizeof(a);i++) //遍历字符串
{
cout<<a[i];
}
cout<<endl;
cout<<a<<endl; //遍历字符串
i=0;
while (a[i]!='\0') { //取得字符串字符个数,不包括\0
i++;
}
cout<<i<<endl;
cout<<strlen(a)<<endl; //取得字符串字符个数,不包括\0
return 0;
}
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char b[32]={"hell\0wrold"};//使用cout直接输出字符串,遇到'\0'会结束。(遍历字符串)
cout<<b<<endl;
return 0;
}
遍历二维字符数组
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
char arr[5][32]={"\0"};
int n=sizeof(arr)/sizeof(arr[0]);
cout<<"输入5个字符串"<<endl;
int i=0;
for(i=0;i<n;i++){
cout<<"输入第"<<i<<"个字符串"<<endl;
cin>>arr[i]; //从键盘获取字符串
}
for(i=0;i<n;i++){ //遍历字符串
cout<<"第"<<i<<"个字符串是:"<<arr[i]<<endl;
}
return 0;
}
函数
函数是c语言的功能单位,实现一个功能可以封装一个函数来实现。
定义函数的时候一切以功能为目的,根据功能去定函数的参数和返回值
需要传哪些数据给函数?(实参)
函数的功能代码(函数体)如何实现?
函数需要返回啥类型的数据?(函数的返回值类型)
函数的分类
定义角度:
库函数(c++语言库)、自定义函数、系统调用(内核提供给用户的函数接口)
有无参数:参数是函数外部数据 到 函数内部的 桥梁
无参的函数:不能将函数外部的数据 传递 给函数内部
有参的函数:通过参数 将函数外部的数据 传递到函数内部
函数的定义
实现函数体,确定函数名,函数的形参、函数的返回值类型
int my_add(int x, int y) //x,y是形参,定义的时候形参不会开辟空间,int是定义返回值的类型
//函数调用的时候 才会为形参 开辟空间 保存实参的值
{
return x + y;//return 返回函数运算结果 结束当前函数,
}
函数声明
先调用函数 后定义函数 需要提前函数声明。或者函数在外部需要声明函数。
函数声明:告知编译器 该函数的函数名是啥 有几个形参 返回值类型是啥
函数的调用
一般调用格式是:函数名(实参);
大量调用函数 会发生 “出入栈”的开销
函数内部如果要修改外部的变量的值,需要传入外部变量的地址
#include <iostream>
#include<string.h>
using namespace std;
extern int my_add(int x, int y); //函数声明
int main()
{
int a=0,b=0;
cout<<"输入第一个数"<<endl;
cin>>a;
cout<<"输入第二个数"<<endl;
cin>>b;
int add=my_add(a,b); //函数调用,a,b是实参
cout<<"和:"<<add<<endl;
return 0;
}
int my_add(int x,int y) //函数定义
{
return x+y;
}
数组作为函数的参数
数值数组作为函数的参数,函数内部 可以 操作(读写) 外部数组的元素。
#include <iostream>
#include<string.h>
using namespace std;
extern void inputIntArr(int arr[],int n); //函数声明,extern内部函数可省略
void printIntArr(int arr[],int n); //函数声明
void sortIntArr(int arr[],int n); //函数声明
int main()
{
int arr[5]={0};
int n=sizeof(arr)/sizeof(arr[0]);
inputIntArr(arr,n); //从键盘获取元素值
sortIntArr(arr, n); //排序
printIntArr(arr,n); //遍历
return 0;
}
void inputIntArr(int arr[],int n)//相当于void inputIntArr(int *arr,int n)
{
int i=0;
for (i=0;i<n;i++)
{
cout<<"输入第个"<<i<<"元素"<<endl;
cin>>arr[i];
}
}
void sortIntArr(int arr[],int n)//相当于void sortIntArr(int *arr,int n)
{
int i=0,j=0;
for(i=0;i<n;i++)
{
for(j=0;j<n-1;j++)
{
if(arr[j]>arr[j+1])
{
int tem=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tem;
}
}
}
}
void printIntArr(int arr[],int n) //相当于void printIntArr(int *arr,int n)
{
int i=0;
for (i=0;i<n;i++)
{
cout<<arr[i]<<endl;
}
}
说明:arr是数组的名字也是数组的地址,函数中的形参int arr[]=int *(arr+0)=int *arr,所以数组作为实参也是传的地址,所以函数内部 可以 操作(读写) 外部数组的元素
给函数传一维数组
void fun(int p[])//形式1
void fun(int *p)//形式2
给函数传二维数组
void fun( int p[][4] )//形式1
void fun( int (*p)[4] )//形式2
传指针数组
void fun(char **q)
void fun(char *q[])
字符数组作为函数的参数
#include<iostream>
#include<string.h>
using namespace std;
int len_str(char str[]);
void my_str(char a[], int n);
int main()
{
char str[32]="\0";
int n=sizeof(str);
my_str(str,n);
int a=len_str(str);
cout<<a<<endl;
return 0;
}
void my_str(char a[], int n)
{
cout<<"输入一个字符串"<<endl;
cin.getline(a,n);
cout<<a<<endl;
}
int len_str(char str[])
{
return strlen(str);
}
预处理
进程:可执行文件 从运行到结束 整个动态的过程 就叫进程。(占内存空间)
在32位平台 每一个进程 占4G空间(虚拟空间)
内存分区
堆区:使用malloc,calloc,realloc,free,new,delete动态申请。可读可写
栈区:局部变量,函数的形参,返回值。可读可写
全局区:普通全局变量,静态全局变量,静态局部变量。可读可写
文字常量区:数值常量,字符常量,字符串常量,符号常量。只读
代码区:代码的二进制指令。只读
普通局部变量
定义形式:在{}里面定义的 普通变量 叫普通局部变量
作用范围:所在的{}复合语句之间有效
生命周期:所在的{}复合语句之间有效
存储区域:栈区普通局部变量 不初始化 内容 不确定
普通局部变量 同名 就近原则(尽量别同名)
void func()
{ //复合语句
int num = 10; //num 局部变量
{
int num = 20; //data 局部变量
cout<<num<<endl;//20 就近原则
}
cout<<num<<endl;//10
}
普通全局变量
定义形式:在函数外定义的普通 变量
作用范围:当前源文件以及其他源文件 都有效。
生命周期:整个进程。
存储区域:全局区
注意事项:
1、全局变量不初始化 内容为0
2、全局变量 和 局部变量 同名 优先选择局部变量。
int data = 10; //普通全局变量
void func()
{
int data = 20;//普通局部变量
cout<<data<<endl;//20
cout<<::data<<endl;//10,通过作用域访问外部的data
}
3、其他源文件 使用全局变量 必须对全局变量 进行extern声明。(变量的使用所在的源文件)extern 声
明外部可用。该变量或函数 来自于其他源文件。
1.cpp
//extern 声明data为int类型 来之其他源文件
extern int data;//声明变量来自于其他源文件(2.cpp)
void add_data(void)
{
data = data+100;
return ;
}
2.cpp
extern void add_data(void);//声明函数来自于其他源文件(1.cpp)
int data = 10; //普通全局变量
int main()
{
add_data();
cout<<"data="<<data<<endl;
}
静态局部变量
作用范围:所在的{}复合语句之间有效
生命周期:整个进程有效
存储区域:全局区
注意事项:
1、静态局部变量不初始化 内容为0
2、静态局部变量 整个进程 都存在(第一次定义有效)
void fun04()
{
static int num=10;//不加static修饰,多次调用函数num一直是11
num++;
cout<<"num = "<<num<<endl;
}
int main()
{
fun04();//num = 11
fun04();//num = 12
fun04();//num = 13
fun04();//num = 14
}
静态全局变量
定义形式:在函数外 加static修饰定义的变量 就是静态全局变量
作用范围:只能在当前源文件使用 不能在其他源文件使用。
生命周期:整个进程
存储区域:全局区
注意事项:
1、静态全局变量不初始化 内容为0
2、静态全局变量 只能在当前源文件使用
int data3 = 10;//普通全局变量
static int data4 = 20;//静态全局变量
void test()
{
}
全局函数
函数默认 都为全局函数
全局函数:在当前源文件 以及其他源文件 都可以使用
如果其他源文件使用需要 extern对全局函数 进行声明
静态函数
加static修饰的函数
静态成员 只能在当前源文件用,其他源文件调用不了此函数
头文件
头文件包含:在预处理 结果 将头文件的内容 原封不动的 包含在 目的文件中
#include <head.h> <>包含系统头文件
<>从系统指定目录 寻找head.h头文件
#include “head.h” " "包含自定义头文件
“ ”先从当前目录 寻找head.h头文件 如果找不到 再到系统指定的目录下寻找
#define 宏
编译四阶段:预处理、编译、汇编、链接
使用关键字 define 定义 叫宏
宏的作用范围:是从定义处开始 到 当前文件结束 都有效
#undef可以结束宏的作用域
宏 没有作用域的限制 只在当前源文件 有效
#define ST 123 (宏定义)
在预处理结果 使用123替换所有出现ST的位置 (宏展开)
不要再宏后加;分号
宏尽量大写和普通变量区分开
不带参数的宏
#define ST 123
#define STR "hello"
#define NUM 100
带参数的宏(宏函数)
#define MY_ADD(a, b) a+b
cout<<MY_ADD(10,20);//10+20
宏的参数不能有类型
#define MY_ADD(int a, int b) a+b //err
宏不能保证参数的完整性
#define MY_MUL(a, b) a *b
cout<<MY_MUL(10, 20); //10*20
cout<<MY_MUL(10 + 10, 20 + 20); //10 + 10*20 + 20 == 230
可以使用()的形式 让带参数的宏 具备一定的完整性
#define MY_MUL(a, b) a *b
#define MY_MUL2(a, b) ((a) * (b))
cout<<MY_MUL(10, 20); //10*20
cout<<MY_MUL(10 + 10, 20 + 20); //10 + 10*20 + 20 == 230
cout<<MY_MUL2(10 + 10, 20 + 20);//((10 + 10) * (20 + 20))==800
宏不能作为结构体、类的成员
宏函数和普通函数
函数有作用域的限制,可以作为类的成员
宏函数没有作用域限制,不能作为类的成员
带参宏的形参不需要类型
带参函数的形参需要类型
带参宏调用多少次就展开多少次,不需要压栈弹栈,浪费空间节省时间
带参函数代码只有一份,存在代码区,调用去代码区取指令,需要压栈弹栈,浪费时间节省空间