大连网站网页设计公司,深圳网站建设伪静态 报价 jsp 语言,wordpress页面如何调用文章分类,国家企业信用公示信息查询系统官网旧文更新#xff1a;两三年的旧文了#xff0c;一直放在电脑里#xff0c;现在直接传上CSDN
一、指针的概念
1.1 指针
程序运行时每个变量都会有一块内存空间#xff0c;变量的值就存放在这块空间中。程序可以通过变量名直接访问这块空间内的数据#xff0c;这种访问方…旧文更新两三年的旧文了一直放在电脑里现在直接传上CSDN
一、指针的概念
1.1 指针
程序运行时每个变量都会有一块内存空间变量的值就存放在这块空间中。程序可以通过变量名直接访问这块空间内的数据这种访问方式称之为直接访问。
而内存中每一个字节都会有一个编号称之为内存地址。我们可以通过直接访问内存地址从而找到变量。在C中有一种指针变量专门用于存储内存地址我们通过访问指针变量可以得到对应变量的内存地址从而实现对该变量的访问。这就是间接访问。
指针存储的是一个内存地址他的一个重要用途就是通过指针间接访问所指向的地址中的内容。指针定义如下 类型名 *指针变量名; 比如定义两个指针p1和p2 int *p1, *p2;
1.2 指针的基本操作
1.指针变量的赋值 指针变量一般用于保存同一个程序中某个变量的地址以便日后使用指针变量进行间接访问。因此赋值有两种办法一是将本程序的某一变量地址赋值给指针变量另一种是将指针变量赋值给另一个指针变量。
让指针变量只想某一变量就是将一个变量的地址存入指针变量但是程序员并不知道变量在内存中的地址为此C提供了一个取地址运算符用于获取指定变量的地址例如
int *p, x;
px;这样就成了将x变量的地址放入到指针p中上述语句等价于int x, *px
和普通变量一样如果没有给新定义的指针变量赋值C会给它随机赋以初址这会导致内存泄漏因此为了避免误操作不要引用没有被赋值的指针并且某个指针被创建了但暂且不用应该给它赋以NULL值。
需要注意的是不同变量类型的指针之间不能相互赋值比如int x;double *p x;这种操作是不允许的因为指针是使用变量类型大小来判断边界的。在内存中int是4字节大小的而double是8字节大小的。那么double指针会以其存储的地址为起点读取往后的8个字节的内容很明显这超过了int型的大小限制。
2.指针变量的访问 C中定义了一个取指针指向值的运算符*该运算符是一个一元运算符他的运算对象是一个指针运算符会根据指针的类型返回其指向的值。这在指针定义之后使用。 也就是说指针在定义的时候需要在变量名前加*但是在后续使用指针变量时候是不需要加*的指针p在被定义后再使用*p的话会直接得出指针所指的变量的值下列是一个简单的实例
int a2, *pa;
cout*p p a;我们可以看到输出结果是2 0x16d81b868 2。也就是在完成定义后p表示内存地址*p表示该内存地址存入的值。
3.统配指针类型void 指针的基本类型可以为void这只说明了这个变量中存放的是内存地址但是并未说明存放何种类型的地址因此任何类型的指针都可以和void类型指针相互赋值。
4.指针和常量限定符const 使用const修饰指针有如下三种用法 1.指向常量的指针常量指针是一个执行内容是常量的指针变量指针可以更改指向的对象但是不能改变指向对象的值。
const int *p x;2.指针常量指针本身是一种常量无法改变指针的值但是可以改变指向的变量的值
int *const px;3.指向常量的指针常量指针本身不可变所指向的值也不能变
const int *const p x;二、指针和数组
2.1 指针运算
指针保存的是一个内存地址本质上是一个整数因此对整数进行算术运算也是十分理算当然得。但是对于指针执行乘除运算是没有意义的因为这会使得指针指向不可知的领域C中只考虑了指针的加减运算。对指针执行1那么他会增加一个基本类型的长度比如对一个int *p1000执行p那么p1004因为整形变量的大小为4。
2.2 用指针访问数组
在C中一个数组的数组名保存的是数组的起始地址也就是说实际上数组名就是一个指针不过它是一个指针常量。不过数组在声明时除了将数组首地址赋值给了数组名外还进行了空间申请的行为。我们完全可以将数组名赋值给一个指针那么该指针就具备了数组名的行为
三、动态内存分配
3.1 动态变量
有时候在C中我们需要动态地新增变量或者说动态指定数组的大小这就需要使用到动态变量机制了。动态变量指的是在写成是时无法确定它们的存在只有程序运行起来随着程序的运行可以根据程序的需求动态产生和消亡的变量。由于动态变量不可以在程序中定义因此也没法给他们取名字因此动态变量的访问需要通过指向动态变量的指针来实现间接访问
3.2 动态变量的创建
C的动态变量的创建使用的运算符是new该运算符可以创建一个简单变量或者一个数组格式如下: new 类型名; 这个操作在内存中称之为堆的区域申请一块能够存放相应数据类型的数据空间完成操作后会返回该空间的首地址。比如要动态产生一个int型变量并且将20赋值给该变量则操作如下
int *p;
p new int;
*p 20;需要注意new操作是需要指定类型的因此它的结果只能赋值给同类指针。 用new操作可以创建一个一维数组格式如下 new 类型名[元素个数]; 动态数组和普通数组最大的区别在于数组的大小不需要静态指明一个常量可以在运行时赋予因此更加灵活。比如
p new int[2*n];3.3 动态变量的消亡
在C运行期间动态变量不会消亡因此要回收动态变量的空间就必须显式地使之消亡。要回收某个动态变量可以使用delete操作。操作如下 delete 指针变量 该操作会回收指针指向的空间例子如下
int *p new int(10);
delete p;如果需要回收的是一个动态数组可以使用delete [] 指针变量 一旦释放了这些内存区域堆管理器会重新回收这些区域虽然指针还会指向这个区域但是已经不能再访问和使用这些区域
在动态变量的使用中最常见的问题是内存泄漏也就是用动态变量机制申请了一个动态变量但是在不需要使用这个动态变量的时候没有delete或者在变量没有delete之前让该动态变量的指针指向另外一个动态变量此时你就彻底弄丢这个动态变量了堆管理器以为你仍在使用它但是你自己都找不到它在哪了。为了避免上述变量应该及时使用delete清除不需要使用的动态变量。
四、指针和函数
4.1 指针作为形式参数
函数的参数可以传入指针变量作用是将一个变量的地址传入到一个函数中指针传递可以降低参数传递的开销并且让主函数和被调用函数共享一块内存空间指针作为形式参数是一种”址传递“在函数中对指针所指向的变量进行操作也会改变该变量的值此时在主函数中读取该变量也是被改变的。而一般参数的”值传递“传递的形式参数的作用域只会是在被调用函数内部对值传递的参数进行修改只会在被调函数中起改变而不会影响到主函数。
但是数组名是一种特殊的情况当数组名作为函数的参数时形式参数和实际参数是共享了同一块内存空间因此函数内对数组形式参数的任何修改都是对实际参数数组的修改。
字符串是作为字符数组存储的因此传递进去的也是指针但是字符串会以’\0’结尾所以可以不传递字符数组的长度
4.2 返回指针的函数
函数返回值可以是一个指针表示函数的返回值是一个指针只需要在函数名之前加一个*号此时返回的值必须是一个指针变量。比如:
五、引用类型
5.1 引用类型
指针提供了通过一个变量间接访问另一个变量的能力。为了获得指针的效果又要避免指针的问题C提供了引用类型这种新的类型。
1.引用的声明和使用 引用就是给变量取一个别名使得一块内存空间可以通过几个变量名在访问。声明引用类型的变量需要在变量名前加上符号并且必须指定初值。比如
int i;
int j i;其中第二个语句中定义了变量j是变量i的别名当编译器遇到这个语句的时候他并不会为变量j分配空间而是只是将i和j的地址关联起来i和j用的是同一内存单元通过j可以访问i的空间。引用实际上是一种隐式指针每次使用引用变量可以不用书写运算符*因此简化了程序的书写。
定义引用类型变量时必须在变量名前加上符号用于区别和普通变量的区别。并且定义时就必须对其进行初始化并赋值。
5.2 引用传递
1.引用传递参数 引用的主要目的是将引用作为参数的函数最经典的是swap函数如果swap函数使用指针书写则如下
void swap(int* a, int* b){int c;c *a;*a *b;*b c;
}很显然如果使用指针传递那么需要在每一个运算符前都加上指针运算符*但是使用引用传递只需要像如下一样书写
void swap(int a, int b){int c;c a;a b;b c;
}可以看到使用引用符号后不需要书写这么多*号了。在使用引用类型参数的时候需要注意调用时对应的实际参数必须为左值表达式
5.3 返回引用的函数
函数的返回值也可以是一个引用代表返回函数内某个变量的引用。