1、using编译命令
1、将using namespace std 放在函数定义之前,让文件中所有函数都可以使用名称空间std中的所有元素;
2、将using namespace std 放在函数定义中,让该函数可以使用名称空间std中的所有元素;
3、在特定函数中使用using std::cout ;这样的编译指令,而不是using namespace std,让该函数可以使用指定的元素,如cout;
4、完全不使用编译指令using,而在需要使用名称空间std中的元素时,使用前缀std::,例如
std::cout << "Chinese" << std::endl;
2、结构体
1、C++允许声明结构变量时省略关键字struct;
2、与C不同,C++结构除了成员变量之外,还允许成员函数,但这些高级特性通常用于类中;
3、声明和初始化指针
3.1、声明指针
1、int *ptr 和 int* ptr; 都是可选的,前者表示*ptr是int类型,而后者表示ptr是int* 类型
2、int *ptr1,ptr2; 前者表示创建int类型指针,而后者表示创建int变量
3.2、初始化指针
指针可以先声明在初始化,也可以声明和初始化一起
int value = 10;
int *ptr1;
ptr1 = &value; //先声明再初始化
int *ptr2 = &value; //声明和初始化一起
3.3、注意
指针可以指向不同类型的变量、函数、结构体等等
1、int *ptr1;
2、double *ptr2;
3、char *ptr3;
4、struct student *ptr4;
但是指针变量本身的长度通常都是相同的,和系统相关
4、什么是OOP
OOP(object oriented programming) 面向对象编程
OOP强调的是在程序运行阶段(而不是编译阶段)进行决策,该属性提供了灵活性,可以根据实际情况进行调整。变量是在编译时分配的有名称的内存,而指针只是为可以通过名称直接访问的内存提供了一个别名。指针真正的用武之地在于,在运行阶段分配未命名的内存以存储值。
5、new和delete用法
5.1、分配和释放单变量
1、typeName *ptr_name = new typeName;
int *ptr1 = new int; //开辟内存
delete ptr1; //释放内存
2、typeName *ptr_name = new typeName(value);
double *ptr2 = new double(66.66);
......
5.2、分配和释放一维数组空间
typeNmae *ptr_name = new typeName[num]; //且num值不必在编译时确定,可以在运行时确定
int *ptr = new int[10]; //数组长度为10的动态数组
delete []ptr;
5.3、分配和释放二维数组空间
在此之前需要了解二维数组的本质:其实也是一维数组,只是这个一维数组的元素类型也是一维数组。
int array[a][b] == int array[][b] == int (*array)[b];
array为数组名,该数组有a个元素,每个元素都是一个数组,且有b个int值组成
eg:int arr[2][3]; //数组长度为2,元素类型为int[3]的一维数组
上述二维数组会被编译器视作一个元素类型为‘int[b]’的一维数组,该数组长度为a。
二维数组的动态创建:
1、使用常量创建
int (*arr1)[b] = new int[a][b]; //创建数组,其中b一定要为常量
理解:arr1为int*指针,指向一个长度为b、类型为int的数组
delete []arr; //释放内存
2、使用指针间接引用
int **arr2 = new int*[a]; //创建
for(i=0; i<a; i++)
{
arr2[i] = new int[b];
}
/*----------------------------*/ //释放
for(i=0; i<b; i++)
{
delete []arr2[i];
}
delete []arr2;
5.4、注意
1、delete释放内存,只会释放指针指向的内存,但是不会删除指针变量本身,也就是说还可以重新指向别的内存;
2、一定要配对的使用new和delete,否则可能发生内存泄露;
3、不用对已经释放的内存重复释放,会导致无法预估的危险;
4、 5.2一维数组中的两式中方括号是非常重要,两者必须配对使用,如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不彻底的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组,delete的方括号中无需填数组元素数,系统自己知道,写了编译器也忽略。
5.5、实例
利用new和delete,根据输入的字符串动态的申请内存,避免直接使用数组存储大量数据,浪费内存。
int main()
{
char * name; // create pointer but no storage
name = getname(); // assign address of string to name
cout << name << endl;
delete [] name; // memory freed
return 0;
}
char * getname() // return pointer to new string
{
char temp[80]; // temporary storage
cout << "Enter last name: ";
cin >> temp;
char * pn = new char[strlen(temp) + 1];
strcpy(pn, temp); // copy string into smaller space
return pn; // temp lost when function ends
}
6、指针常量和常量指针
const int *ptr1; //常量指针:指针指向可改,但指向的内容不可改
int *const ptr2; //指针常量:指针指向不可改,但指向的内容可改
C++禁止将const地址赋给非const指针,但是非const指针可以赋给const指针
1、 const数据的地址只能赋给const指针
const int value1 = 100;
int *ptr1 = &value1; //invalid
const int *ptr2 = &value1; //valid
这是因为如果可以通过指针修改value值,会使得将value定义为const显得荒谬
2、 int value2 = 100;
int *pt3 = &value2; //valid
const int *ptr4 = ptr3; //valid,但是不能通过指针修改内容
//上述为一级间接关系,全部合法
3、对于数据本身不是指针的数据,可以将const数据或者非const数据的地址赋给指向const的指针
int value3 = 100;
const int value4 = 100;
const int *ptr5;
ptr5 = &value3; //valid
ptr5 = &value4; //valid
7、C++管理数据内存
三种方式:自动存储、静态存储、动态存储
1、 自动存储:函数内部定义的常规变量,被称为自动变量(局部非static变量)
一般在所述函数被调用自动产生,函数调用结束时消亡;
通常存储在栈中;
2、 静态存储:分为全局变量和static变量
通常放在全局区
(后序更新)
3、 动态存储:使用new分配,存储在堆中;
8、读取数字的循环
情境:定义了一个整型数组,但是输入了char数据:会出现下面情况:
1、n的值保持不变;
2、不匹配的输入将被留在输入队列中;cin对象中的一个错误标记被设置;
3、不匹配的输入将被留在输入队列中;cin对象中的一个错误标记被设置;
4、对cin方法的调用将返回false(如果被转换为bool类型);
因此在输入错误之后回返回false,可以用做退出循环的标志,且错误标记要重置,才可以继续输入,使用cin.clear()重置。
int Max = 5;
int golf[Max];
cout << "Please enter your golf scores.\n";
cout << "You must enter " << Max << " rounds.\n";
int i;
for (i = 0; i < Max; i++)
{
cout << "round #" << i+1 << ": ";
while (!(cin >> golf[i])) {
cin.clear(); // reset input
while (cin.get() != '\n')
continue; // get rid of bad input
cout << "Please enter a number: ";
}
}
输入数字则返回true,!(cin >> golf[i])为false,结束此次循环,输入字符时,!(cin >> golf[i])为true,进入内部循环,首先使用cin.clear()重置标志位,在while中使用cin.get()读取换行符之前的所有输入,从而删除这一行的错误输入!
9、函数
9.1、函数三要素
1、函数声明(函数原型)
2、函数调用
3、函数定义
对于函数声明:是为了告知编译器:函数返回值类型、参数类型和数量(可以不包含参数变量名,但定义中必须包含);
对于函数调用:使用该函数的接口;
对于函数定义:函数的具体功能实现;
9.2、函数和一维数组
将数组作为参数传递给函数的用法:实质上是将数组名视为指针。
1、void func(int array[],int len);
2、void func(int *array,int len);
/*-----------------------------*/
1、void func(int array[],int len)
{
//可以直接使用数组表示法
}
2、void func(int *array,int len)
{
//可以直接使用数组表示法
}
上述对数组的操作,在函数中会对原始数组进行修改,为了防止无意修改,在声明时可以使用const关键字
9.3、函数对数组指定区间操作
int array[20] = {......};
void func(int *arr_begin,int *arr_end); //声明
func(array+5,array+10);
void func(const int *arr_begin,const int *arr_end)
{
const int *ptr;
for(ptr = arr_begin; ptr <= arr_end; ptr++)
{
//operation
}
}
9.4、函数和二维数组
1、void func(int array[][b],int len);
2、void func(int (*array)[b],int len);
将int (*array)[b]理解为一个指向由b个int数据组成数组的指针,具体查看上述5.3二维数组的本质
此时只规定了数组的列数,没有规定行数,所以传入第二个参数len表示数组的行数
/*-----------------------------*/
1、void func(int array[][b],int len)
{
//可以直接使用数组表示法
}
2、void func(int (*array)[b],int len)
{
//可以直接使用数组表示法
}
10、函数与字符串
10.1、字符串做函数参数
字符串作为参数来传递时,实际传递的是字符串中第一个字符的地址,即char*
void str_func(const char * str,char ch);
char t_str[] = "aabbccddeeffgghh";
str_func(t_str,'b');
11、函数指针
11.1、获取函数地址
函数地址即函数名:
1、function1(func1); //传递的是函数地址
2、function2(func2()); //传递的是函数返回值
11.2、声明函数指针
1、先写函数原型:
double func(int value); //函数原型
2、使用(*p_fun)替换函数名就是指向该函数的指针
double (*p_func)(int value); //声明函数指针