4.内存分配与释放
C语言:
内存的分配与释放使用malloc和 free
有可能会产生野指针(随机指向一块内存的指针),造成内存泄漏
避免产生野指针的六大习惯:
l 养成良好的编程习惯
l 当定义一个没有指向的指针时,将其指向NULL。(NULL代表内存的0地址,并且NULL是不允许做任何操作的)
l 当想要向指针指向的内存空间操作时,用malloc分配内存。(在堆空间里分配内存)
l 清空内存中的数据 (malloc分配的空间里可能存在垃圾值,因此我们需要清空,可以用到
l 使用内存
l 释放内存(free,这时ptr又变成野指针,需再次将它置为空)
C++:
C++中通过new关键字动态内存分配申请,动态内存分配申请是基于类型进行的
变量申请: 数组申请
Type *pointer = new Type; Type *pointer = new Type[N];
通过delete进行内存释放
delete pointer; delete [] pointer;
new 与 malloc的区别:
new是C++的一部分(运算符),而malloc是C语言调用的一个函数
new是以具体类型为单位进行内存分配的,而malloc是以字节为单位进行分配的
new在申请单各类型变量是可进行初始化,malloc不可以
例 int * p = new int(5);
动态分配二维数组:int (*pp)[2] = new int [2][2];
三维数组:int (*ppp)[6][6] = new int [6][6][6]
拓展:传参规则
#include<stdio.h>
voidfunc1(char *ptr) //一维数组用首元素的地址来接
{
printf("func1 = %s\n",ptr);
}
voidfunc2(char (*ptr)[100]) //二维数组用一维数组的地址来接
{
int i;
for(i = 0; i < 2; i++)
{
printf("func2 =%s\n",ptr[i]);
}
}
voidfunc3(char **ptr) //一维数组用首元素的地址来接
{
int i;
for(i = 0; i < 3; i++)
{
printf("func3 =%s\n",ptr[i]);
}
}
intmain()
{
char ptr[100] = "hello world";
char str[2][100] = {"hello","world"};
char *ktr[3] ={"hello1","hello2","hello3"};
func1(ptr);
func2(str);
func3(ktr);
return 0;
}
5.引用与指针
1.引用是给变量起别名
一般格式:类型 &引用名 = 变量名 例:int a = 1; int &b = a;
注意:定义引用时一定要初始化,指名该引用变量的别名
实际应用中,引用一般用作参数传递与返回值
作参数传递时:
例:void swap(int &a, int &b)
引用作为参数对形参的任何操作都能改变相应的实参的数据,又使函数参数的调用显的方便,自然
作返回值时:
可以将函数放在赋值运算符的左边
注意:不能返回对局部变量的引用
#include<iostream>
usingnamespace std;
inttemp = 6;
int& add(int &num)
{
return temp;
}
intmain()
{
int num = 5;
add(num) = 7;
cout << temp<<endl;
return 0;
}
引用与指针的区别:
引用访问一个变量是直接访问,而指针是间接访问。
引用是一个变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间。
引用已经初始化不能再引用其他变量,而指针可以。
尽可能的使用引用,不得已时使用指针。
6.函数升级
(1)内联函数:
内联函数与宏函数的区别:
内联函数调用时,要求实参和形参的类型一致,另外内联函数会先对实参表达式进行求值,然后传递给形参;而宏调用只用实参简单地替换形参。
内联函数是在编译的时候,在调用的地方将代码展开的,而宏则是在预处理时进行替换的。
(内联:以空间换时间 宏函数:以时间换空间)
内联函数的使用:
inlineint max(int a,int b)
{
returna>b?a:b;
}
#defineMAX(a,b) (a)>(b)?(a):(b)
(2)重载函数:
相同的作用域,如果两个函数名称相同,而参数不同,我们把它们称为重载overload
函数重载的条件
函数重载的条件:(函数的返回值不能作为条件)
·函数重载不同形式:
·形参数量不同
·形参类型不同
·形参顺序不同
·形参数量和形参类型都不同
·调用重载函数时,编译器通过检查参数的个数、类型和顺序来确定相应
的被调用函数
namemanagling与extern “C”:
name managling 这里把它翻译为名字改编
·C++为了支持重载,需要进行name managling
·extern “C”实现了C与C++混合编程
#ifdef__cpluscplus
extern “C”
{
#endif
……
#ifdef__cpluscplus
}
#endif
(3)带默认参数的函数:
·函数没有声明时,在函数定义中指定形参的默认值
·函数既有定义又有声明时,声明时指定后,定义后就不能再指定默认值
·默认值的定义必须遵守从右到左的顺序,如果某个形参没有默认值,则
它左边的参数就不能有默认值
voidfuncl(int a,double b = 4.5,int c = 3) //合法
voidfuncl(int a = 1,double b ,int c = 3) //不合法
·函数调用时,实参与形参按从左到右的顺序进行匹配
7.命名空间-namespace
(1) 命名空间
C语言:
·在C语言中只有一个全局作用域
·C语言中所有的全局标识符共享一个作用域
·标识符之间可能有冲突
C++:
·C++中提出了命名空间的概念
·命名空间将全局作用域分成不同的部分
·不同命名空间中的标识符可以同名而不会发生冲突
·命名空间可以相互嵌套
·全局作用域也叫默认命名空间
(2)如何定义命名空间
namespaceFirst
{
int i = 0;
}
namespaceSecond
{
inti = 1;
}
usingnamespace First;
intmain()
{
cout<<i<<endl;
cout<<Second::i<<endl;
return0;
}
(3)如何使用命名空间
·使用整个命名空间:using namespace name;
·使用命名空间中的变量:using name::variable;
·使用默认命名空间中的变量: ::variable
默认情况下可以直接使用
默认命名空间中的所有标识符