例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的详细使用情况和方法,详见: