C语言日记 26 指针与函数,动态存储分配

 例6-7 

输人的两个整数按大小顺序输出。要求用指针类型的数据作函数参数处理。

源程序:

#include<iostream>
using namespace std;
int main()
{
    void swap(int* pl, int* p2);//函数声明
    int* pointer_1, * pointer_2, a, b;
    //定义指针变量pointer_1、pointer_2,整型变量a、b
    cin >> a >> b;
    pointer_1 = &a;//使pointer_1 指向a
    pointer_2 = &b; if (a < b)//使pointer_2 指向b
        swap(pointer_1, pointer_2);
    //如果 a<b,使*pointer_1和*pointer_2互换,
    //不能写成if(a<b) swap(*pointer_1,*pointer_2);
    //因为如果这样的话此时输入的2个参数所代表的东西就变成了
    //他们指向的变量的实际的值

    cout << "max=" << a << " min=" << b << endl;
    //a已是大数,b是小数
    return 0;
}
void swap(int* pl, int* p2)
//函数的作用是将*p1的值与*p2 的值交换
//指的是将指针变量p1的值和指针变量p2的值
//(代表的其实是一个它指向的变量的地址的值)交换

{
    int temp;
    temp = *pl;
    *pl = *p2;
    *p2 = temp;
}
 

#include<iostream>
using namespace std;
int main()
{
	void swap(int* pl, int* p2);//函数声明
	int* pointer_1, * pointer_2, a, b;
	//定义指针变量pointer_1、pointer_2,整型变量a、b
	cin >> a >> b;
	pointer_1 = &a;//使pointer_1 指向a
	pointer_2 = &b; if (a < b)//使pointer_2 指向b
		swap(pointer_1, pointer_2);
	//如果 a<b,使*pointer_1和*pointer_2互换,
	//不能写成if(a<b) swap(*pointer_1,*pointer_2);
	cout << "max=" << a << " min=" << b << endl;
	//a已是大数,b是小数
	return 0;
}
void swap(int* pl, int* p2)
//函数的作用是将*p1的值与*p2 的值交换
{
	int temp;
	temp = *pl;
	*pl = *p2;
	*p2 = temp;
}

结果:

书P100图解注释(实际上真的大可不必,我写这个注释和书上的图我感觉都是画蛇添足)

第一步:输入a,b;

第二步:把a,b的地址传(赋)给pointer_1,pointer_2;
(输出指令,让pointer_1,pointer_2去找a,b的地址并且记住(计入))

(如果(a<b))

第三步:调用swap()函数

(1)先是形参p1和实参pointer_1去找a的地址记住

(2)然后形参p2和实参pointer_2去找b的地址记住

(3)在形参里面p1的数值改了,与此同时a的值也同时发生一样的改变。pointer_1和p1仍指向a。

同理:

(4)在形参里面p2的数值改了,与此同时b的值也同时发生一样的改变。pointer_2和p2仍指向b。

第四步:输出语句时实参pointer_1,pointer_2通过找a,b的位置得到对应的值并输出。


例6-8

使用函数返回一维数组最大值元素,要求用返回指针值的函数实现。

源程序:

#include<iostream>
using namespace std;
int* max(int n)//定义指针函数
{
	static int a[] = { 13, 24, 38, 27, 11, 9, 36, 18 }; int i, m = 0;
	for (i = 1; i < n; i++)
		if (a[m] < a[i])
			m = i;
	return &a[m];
}
void main()
{
	int* p;
	int* max(int n);
	p = max(8);
	cout << "max is " << *p << endl;
}

结果:

关于此时变量i和m是不是静态变量(实际上不是),详见:

C语言日记 19 局部变量(和全局变量),变量的生存期和存储类别_宇 -Yu的博客-CSDN博客

例6-9

指向函数的指针和指向函数的指针数组。

源程序:

#include<iostream>
using namespace std;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a > b ? b : a; }
int ave(int a, int b) { return (a + b) / 2; }
void main()
{
	int a = 10, b = 15, c, (*pc)(int, int), (*p[2])(int, int);
	pc = ave; p[0] = max; p[1] = min;
	c = (*pc)(a, b);	//调用 pc 所指函数
	cout << "平均值是:" << c << endl;
	c = (*p[0])(a, b);
	cout << "最大值是:" << c << endl;//调用 p[0]所指函数
	c = (*p[1])(a, b);
	cout << "最小值是:" << c << endl;
}

其中的“(*p[2])(int, int)”;就是

数组名作为(指向函数的指针的)指针变量名、

指向函数的指针整个运行过程:(这里)

输入实参a和b(给到指针),指针又指向函数(功能)

于是就实现了把实参a和b输入到函数中的效果(结果)

 结果:

动态存储分配


delete:

 书P103:

delete p:只是释放*p中的内容,而不改变指针p本身,P存放的依然是申请空间时的地址。

然而,事实上不仅仅是那么简单,delete还对指向的变量本身的地址做了改动,首先我们要声明:

a和(&a)也不一样,或者说:

指针内部存放的目标对象的地址和指针本身的地址还是完全不一样,完全就是两回事:

#include <iostream>
using namespace std;
int main()
{
	int* a = new int(4);
	cout << a << endl;//a作为指针储存的数值为
	//指向的目标常量4的(存储)地址
	cout << &a << endl;//指针a本身的存储地址
	cout << *a << endl;//指向的目标常量4的值
}

结果:

而对于delete对*p中的内容指针p本身,指向的变量本身及其地址有没有做改变的操作

下面我们将设计如下程序验证:

#include <iostream>
using namespace std;
int main()
{
	int* a = new int(4);
	int* b = new int[100];
	{
		cout << "a指向的目标常量4的地址:" << a << endl;
		cout << "指针a本身的存储地址:" << &a << endl;
		delete a;
		cout << "a指向的目标常量释放内容后的地址:" << a << endl;
		cout << "释放内容后指针a本身的存储地址:" << &a << endl;
	} 
	cout << endl;
	{
		cout << "b指向的目标常量的地址:" << b << endl;
		cout << "指针b本身的存储地址:" << &b << endl;
		delete[] b;
		cout << "b指向的目标常量释放内容后的地址:" << b << endl;
		cout << "释放内容后指针b本身的存储地址:" << &b << endl;
	}
};

结果:

并且 

 最终(总的来说),观察上述程序与结果输出中我们可以得到结论:

delete:

  • 清除指针中存储的(目标对象的地址)内容
  • 不改变指针本身的地址
  • 清除指向的目标本身
  • 清除指向的目标地址


new:

例6-10 开辟空间以存放一个二维数组。

源程序:

#include <iostream>
using namespace std;
int main()
{
	int i, j;
	int** p;
	p = new int* [4];
	//开始分配4行8列的二维数据
	for (i = 0; i < 4; i++)p[i] = new int[8];
	for (i = 0; i < 4; i++)	//给二维数组放入数据
	{
		for (j = 0; j < 8; j++)p[i][j] = j * i;
	}
	//打印数据
	for (i = 0; i < 4; i++)
		for (j = 0; j < 8; j++)
		{
			if (j == 0) cout << endl;
			cout << p[i][j] << "\t";
		}
	for (i = 0; i < 4; i++)
		delete[] p[i];
	delete[] p;
	return 0;
}//1

结果:

  这里的

    p = new int* [4];

他想表示的,应该就是所谓

    int(*p)[8];

的这个意思,但是对于开辟二级(维)指针空间的使用规则和规范,书上没有明确说明,比如:

    p = new int(*p) [4];

就不行:

所以,开辟这种多维指针类型的二级(维)指针空间的使用规则和规范到底是什么?!

当使用new运算符定义一个多维数组变量或数组对象时,它产生一个指向数组第一个元素的指针

返回的类型保持了除最左维数外的所有维数。例如:  

int* p1 = new int[10];

开辟了一个一维数组,返回一个指向该int型存储空间的地址(即指针)(int*  )

int(*p2)[10] = new int[2][10];

开辟了一个二维数组, (去掉最左边那一维[2], 剩下int[10], 所以)

返回的是一个指向int[10]这种一维数组型存储空间的地址(即指针)(int (*)[10] ) 


下面,我们再延展(拓展)至三维:

int(*p3)[2][10] = new int[5][2][10];

开辟了一个三维数组, (去掉最左边那一维[5],剩下int[2][10], 所以)返回的是一个指向int[2][10]这种二维数组型存储空间的地址(即指针)(int (*)[2][10]) 

C++中用new动态创建二维数组的一般格式为:

TYPE (*p)[N] = new TYPE [][N];

TYPE:类型,N:二维数组的列数。

采用这种格式,列数必须指出,而行数无需指定。在这里,p的类型是TYPE*[N],即是指向一个有N列元素数组的指针。


还有一种方法,可以不指定数组的列数:(本例我们这里用的就是这种方法)
 

    int** p; 
    p = new int*[10];  
    //注意,int*[10]表示一个有10个元素的指针数组
    for (int i = 1; i <= 10; i++)p[i] = new int[5];

{

指针数组:

数组元素为指针的数组,其本质为数组。(例如 int *p[3],定义了p[0],p[1],p[2]三个指针)

}

这里,二级指针**p的指针名p为"int **" 类型(也就是说是一个指向int[10]这种一维数组型存储空间(like:int (*)[10]) 的地址(即指针))

具体赋给二级指针**p指针名p的(一个指向int[10]这种)一维数组(一个(10个元素的)指针数组)型存储空间的地址(即指针))。

我们可以很容易就注意到:

这里的“**p”和我们在C语言日记 25(2) 补充:二维数组与指针理解具体过程详解_宇 -Yu的博客-CSDN博客(里面的:A[3][3],int**p=A;执行p++时,编译器因无法知道长度(列宽:一行有多少列)而用不了)中提到的“(*p)[5]”他们的指针名代表的意义截然不同:

(*p)[5]中的数组名p,其实表示的是一个行地址

和这里完全不一样的地方:p也代表整个二维数组的首(个)元素(整个二维数组的第0行)的内存的首(元素的)地址;

当然和这里很像的是,它本身代表着一个一维数组,“[5]"表示一维数组包含5个元素

而这里,在开辟存储空间时,**p中的数组名p,表示的是一个一维数组型存储空间的地址


另外,这里这个程序却(是)不能改成

    int(*p)[8];

的形式:

#include <iostream>
using namespace std;
int main()
{
	int(*p)[8];
	int i, j;
	p = new int* [4];
	//开始分配4行8列的二维数据
	for (i = 0; i < 4; i++)p[i] = new int[8];
	for (i = 0; i < 4; i++)	//给二维数组放入数据
		for (j = 0; j < 8; j++)p[i][j] = j * i;
	//打印数据
	for (i = 0; i < 4; i++)
		for (j = 0; j < 8; j++)
		{
			if (j == 0) cout << endl;
			cout << p[i][j] << "\t";
		}
	for (i = 0; i < 4; i++)
		delete[] p[i];
	delete[] p;
	return 0;
}//1

结果:

 这又是为什么?

其实原因很简单:

因为我们这里用的p是一个指针数组,而不是一个数组指针;

{

数组指针:

指向数组地址的指针,本质上就是个指针;

指针数组:

数组元素为指针的数组,其本质为数组。(例如 int *p[3],定义了p[0],p[1],p[2]三个指针)

}


不知道他搞什么鸡毛,我感觉明明这俩程序一模一样,结果下面这个程序输入以后全是一堆报错:

#include <iostream>
using namespace std;
int main()
{
	int i,j;
	p = new int* [4];
	int** p;
	//开始分配4行8列的二维数据
	for (i = 0; i < 4; i++)p[i] = new int[8];
	for (i = 0; i < 4; i++)	//给二维数组放入数据
	{
		for (j = 0; j < 8; j++)p[i][j] = j * i;
	}
	//打印数据
	for (i = 0; i < 4; i++)
		for (j = 0; j < 8; j++)
		{
			if (j == 0) cout << endl;
			cout << p[i][j] << "\t";
		}
	//开始释放申请的堆
for (i = 0; i < 4; i++)
	delete[] p[i];
delete[] p;
return 0;
}

谁能搞清楚是怎么回事???

main()函数的括号部分打成了中文输入法..

麻了,我nm裂开

另外,对于后面我们学数据结构时补充完整了关于new的详细使用情况和方法,详见:

数据结构与算法基础(王卓)(8)附:关于new的使用方法详解_宇 -Yu的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值