C++(七)指针

一、地址与指针

日常生活中我们会问一个人住在哪,比如小明家住在XX省XX市XX县XX镇XX村,这就是其详细住址,也就是地址。
那么在程序中定义的任何变量实际上都是存在内存中的,那么他们的具体位置是多少呢,这里就涉及到了地址。就是这个变量真正存在的位置。
下面我们用代码举个例子,例如定义一个字符:
char ch = ‘a’;
我们用vs的监视窗口来看下字符 ch 的地址是多少呢?
那么在使用 cout << ch; 进行输出的时候,cout 也会去从 ch 的地址开始读取一个字符,之后打印输出出来。

变量的地址一般都是比较难记的,例如:0x007f2eab 之类的,那么能不能用专门的一个东西,或者说一种特殊类型的变量来保存这个地址呢?这个特殊类型的变量就是指针。

定义指针及初始化

int* p; //声明了一个指向int类型的指针,就在类型的后面加上一个*,代表是指针类型变量的意思。
但是他没有指向任何变量的地址。

#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
    //定义的时候初始化
	int a = 5;
	int* ptr = &a;
	*ptr = 6;                     //间接修改了a的值
	cout << "a=" << a << endl;

	// 先定义后初始化
	int a = 5;
	int *q;
	q = &a;
	return 0;
}
===============
以上输出:a=6
  1. 将一个int类型的指针p指向了int类型变量a的地址。&符号是取地址符号,&a 就是取变量a的地址。
    指针p也是一个变量,只不过是一个指针类型的变量,所以指针变量p的值就是 &a,指针变量p的地址是 &p。也就是说指针变量也是变量,他也有内容和地址。
  2. 在指针变量的前面加上一个*就能得到指针指向的变量自身。
    所以对一个变量的修改,既可以通过该变量自身(直接修改),也可以通过指针/地址来实现修改(间接修改)。

说明:
①、指针变量的定义格式如下:基类型 * 指针变量名;
②、符号* 既可以靠近基类型,也可以靠近指针变量名,例如:int* p; 和 int *p; 都是正确的。
③、指针变量可以在定义的时候就初始化,也可以先定义后初始化,也可以在以后的任意一个时间去指向某个变量的地址:
④、基类型就是该指针变量指向的变量的类型。例如: int* ptr; 就是定义了一个指向int类型的指针变量ptr;你就不能把一个float类型的变量地址赋给他。
⑤、指针变量可以指向同一类型的变量,例如:
int a = 5, b = 6;
int *p = &a;
p = &b;
即:指针变量p既可以指向变量a的地址,也可以指向变量b的地址。

定义一个函数,实现交换两个参数的值:

void swap(int* pa, int* pb)
{
    int t = *pa;
    *a = *b;
    *b = t;
}
二级指针

如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。
假设有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量,它们的关系如下图所示:
在这里插入图片描述
int a =100;
int *p1 = &a;
int **p2 = &p1;

指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号*。p1 是一级指针,指向普通类型的数据,定义时有一个*;p2 是二级指针,指向一级指针 p1,定义时有两个*。

二、指针与数组

之前我们知道如何 定义数组,在这里我们定义一个指针的数组,用来保存之前那个数组的所有元素的地址。如下:

int num[100] = {0};
int* pnum = &num[0];     // 或者这样写:int* pnum = num;
for(int idx = 0; idx < 100; ++idx)
{
    p_num[idx] = &num[idx];
}

①、C/C++中规定数组名字就是数组的首地址。也就是数组的第0个元素的地址。
②、C/C++中规定如果指针变量pnum已经指向数组中的一个元素,则pnum+1指向同一数组中的下一个元素的地址(而不是将pnum的值简单+1)。
③、访问数组的两种方法:
  下标法:num[0];
  指针法:*(pnum+idx)
  小案例:指针遍历数组:

#include "stdafx.h"
#include <iostream>
using namespace std;

int main()
{
	int num[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int* pnum = num;
	for (int idx = 0; idx < 10; ++idx)
	{
		cout << *(pnum + idx) <<",";
		// cout << *pnum++ << ","; 效果同上一行
	}
	cout << endl;
	return 0;
}
===========运行输出============
0,1,2,3,4,5,6,7,8,9,

④指针运算(算术)
从上例你也可以得出:比如 int 类型指针pnum,pnum++ 他会指向下一个int的地址。

int num_aaa[11] = {5,2,3,4,5,6,7,8,9,1,0};
int *pt = num_aaa;       // 指向第一个元素 5;假设首地址为5000
pt++;                    // 此时指向第二个元素 2;此时指向地址为5004
int *pe = &num_aaa[9];   // 指向第十个元素 1;此时指向地址为5036
pe--;                    // 指向第九个元素 9,即num_aaa[8];此时指向地址为5032
int diff = pe - pt       // diff=7,此时获取num_aaa[8]~num_aaa[1]之间的元素
字符指针与字符数组

定义两个字符数组输入如下:
用指针的方式,实现将 str2 拷贝到 str1 中。

int main()
{
	char *p = new char[6];
	char *a = "hallo";     //或 char a[] = "hallo";
	strcpy(p, a);
	cout << p << endl;
}

小案例:字符指针数组

void print_char(char* array[], int len);  //函数声明  


int main(void)
{
	char *a[] = { "abc","cde","fgh" };       //字符指针数组  
	char* *b = a;                            //定义一个指向指针的指针,首地址指向字符串的首地址 `abc\0`
	cout << *b << "," << *(b + 1) << "," << *(b + 2) << endl;
	cout << "================" << endl;

	char* test[] = { "abc","cde","fgh" };    //指针数组元素为字符串
	int num = sizeof(test) / sizeof(char*);  //计算字符串个数  
	print_char(test, num);
	return 0;
}

void print_char(char* array[], int len)      //传递指针数组地址,每加1也就是加上sizeof(char*)的长度  
{
	for (int i = 0; i < len; i++)
	{
		cout << *array++ << endl;
	}
}
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;



struct student
{
	int num;
	char *name;
	char sex;
	float score;
};

int main()
{
	student stu_01[5] = {
		{ 101,"Zhou ping",'M',45 },
		{ 102,"Zhang ping",'M',62 },
		{ 103,"Liou fang",'F',92 },
		{ 104,"Cheng ling",'F',87 },
		{ 105,"Wang ming",'M',58.0 },
	};
	student *ps = stu_01;                                                      //定义结构指针变量
	for (ps = stu_01; ps < stu_01 +(sizeof(stu_01)/sizeof(stu_01[0])); ps++)   //结构变量指针指向结构数组首地址(也就是函数名)
	{
		cout << "ps->num, ps->name, ps->sex, ps->score:" << (ps->num, ps->name, ps->sex, ps->score)<< endl;
	}
	return 0;
}
==================运行输出======================
ps->num, ps->name, ps->sex, ps->score:45
ps->num, ps->name, ps->sex, ps->score:62
ps->num, ps->name, ps->sex, ps->score:92
ps->num, ps->name, ps->sex, ps->score:87
ps->num, ps->name, ps->sex, ps->score:58

三、指针与动态数组

new 分配内存

在C语言中,使用库函数malloc()来分配内存,在C++中仍然可以使用,但还要更好的方法new运算符。
new其实就是告诉计算机开辟一段新的空间,但是和一般的声明不同的是,new开辟的空间在堆上,而一般声明的变量存放在栈上。通常来说,当在局部函数中new出一段新的空间,该段空间在局部函数调用结束后仍然能够使用,可以用来向主函数传递参数。另外需要注意的是,new出来的是一段空间的首地址。所以一般需要用指针来存放这段地址。

通用格式如下:
typeName * pointer_name = new typeName;

示例如下:

#include <iostream>
#include <string>
using namespace std;

struct student
{
    string name;
    int age;
};

 
int main()
{
    int *pn = new int;       //申请 int 类型内存
    int *pm = new int(3);    //可以在new后面直接赋值
    
    int *pl = new int;       //先声明再赋值 
    *pl = 3;
    
    int q = *new int;        //也可以定义一个变量,在new之前用“*”表示new出来的内容
    q = 1;
    
    
    int *qo = new int[3];     //new一个数组(包含3个int元素的数组)
	
	//new一个结构体数组
    student *stu = new student[3]{{"abc", 90}, {"bac", 78}, {"ccd", 93}};
    return 0;
}
delete 释放内存

释放通过new申请的内存

#include <iostream>
#include <string>
using namespace std;

struct student
{
	char name[20];
	float height;
	double age;
};


int main()
{
	student *ps = new student;       // 申请内存
	cout << "请依次输入姓名(20个字符);身高(小数);年龄(整数):" << endl;
	cin.get(ps->name, 20);
	cin >> (*ps).height;
	cin >> ps->age;

	cout << "Name:" << (*ps).name << endl;
	cout << "Height:" << ps->height << endl;
	cout << "Age:" << ps->age << endl;
	delete ps;                      // 释放内存
	return 0;
}

小案例二:

  1. 申请指向动态存储的结构数组的指针。
  2. 遍历输入与输出。

以下代码有点问题,求教

#include "stdafx.h"
#include <iostream>
using namespace std;


struct student
{
	char name[20];
	float height;
};


int main()
{
	student *ps = new student[2];       // 申请内存
	
	for (int i = 0; i < 2; i++) 
	{
		cout << "请输入第 " << i+1 << " 个姓名(20个字符);身高(小数);" << endl;
		cin >> ps->name;
		cin >> ps->height;
		ps++;
	}
	ps -= 3;
	for (int i = 0; i < 2; i++)
	{
		cout << "Name:" << ps->name << " Height:" << ps->height << " cm" << endl;
	}

	delete [] ps;                      // 释放内存
	return 0;
}
发布了391 篇原创文章 · 获赞 607 · 访问量 74万+

猜你喜欢

转载自blog.csdn.net/wsp_1138886114/article/details/104312537