指针定义
p是一个指针,代表的是存储的值的地址;
*p是存储在地址中的值。
//创建变量a,将值1存储在该变量中
int a = 1;
//创建变量pa,将变量a的地址存储在pa中
int* pa = &a;
//强调*p是一个int类型的值——C程序员
int *p;
//强调int*是一种类型——C++程序员
int* p;
指针变量进行函数传参——交换两个变量的值
函数的参数不仅可以是整数、小数、字符等具体的数据,还可以是指向它们的指针。
用指针变量作函数参数可以将函数外部的地址传递到函数内部,使得在函数内部可以操作函数外部的数据,并且这些数据不会随着函数的结束而被销毁。
像数组、字符串、动态分配的内存等都是一系列数据的集合,没有办法通过一个参数全部传入函数内部,只能传递它们的指针,在函数内部通过指针来影响这些数据集合。
……
startTest();
……
void MainWindow::startTest()
{
qDebug() << "asd";
int a = 1;
int b = 2;
swap(a, b);
qDebug() << a << b;
}
//Qt中除了构造函数和析构函数,都要加上void或double的类型
void MainWindow::swap(int a, int b)
{
qDebug() << a << b;
int temp = a;
a = b;
b = temp;
qDebug() << a << b;
}
asd
1 2
2 1
1 2
a、b 的值并没有发生改变,交换失败。
生存周期不一样,以函数里定义的局部变量,在函数运行完之后就会结束,在swap函数中确实可以交换数据,但是无法在函数外部进行显示其变化
这是因为 swap() 函数内部的 a、b 和 main() 函数内部的 a、b 是不同的变量,占用不同的内存,它们除了名字一样,没有其他任何关系
swap() 交换的是它内部 a、b 的值,不会影响它外部(main() 内部) a、b 的值。
……
pStartTest();
……
void MainWindow::pStartTest()
{
qDebug() << "asd";
int a = 1;
int b = 2;
//调用 pSwap() 函数时,将变量 a、b 的地址分别赋值给 p1、p2(都是地址)
pSwap(&a, &b);
qDebug() << a << b;
}
void MainWindow::pSwap(int* p1, int* p2)
{
qDebug() << *p1 << *p2;
int temp = *p1;
*p1 = *p2;
*p2 = temp;
qDebug() << *p1 << *p2;
}
函数运行结束后虽然会将 p1、p2 销毁,但它对外部 a、b 造成的影响是“持久化”的,不会随着函数的结束而“恢复原样”。
asd
1 2
2 1
2 1
指针变量进行函数传参——数组作函数参数
#include <stdio.h>
//C++系列专属
#include <iostream>
using namespace std;
int max(int *intArr, int len)
//int类型的可以不用声明,但是void类型必须声明
int max(int *intArr, int len) {
int i, maxValue = intArr[0]; //假设第0个元素是最大值
for (i = 1; i < len; i++) {
if (maxValue < intArr[i]) {
maxValue = intArr[i];
}
}
return maxValue;
}
int main() {
int nums[6], i;
int len = sizeof(nums) / sizeof(int);//可以得到长度
//读取用户输入的数据并赋值给数组元素
for (i = 0; i < len; i++) {
//scanf_s("%d", nums + i);
//不可以使用nums++,是因为是常量指针
cin >> nums[i];//常量指针
}
//printf("Max value is %d!\n", max(nums, len));
//max函数的返回值是int类型的值,可以直接写
cout << max(nums, len);//nums是数组变量名,也就是数组的首地址
system("pause");
return 0;
}
12 55 30 8 93 27↙(enter)
Max value is 93!
参数 intArr 仅仅是一个数组指针,在函数内部无法通过这个指针获得数组长度,必须将数组长度作为函数参数传递到函数内部(必须)。
数组 nums 的每个元素都是整数,scanf() 在读取用户输入的整数时,要求给出存储它的内存的地址,nums+i就是第 i 个数组元素的地址。
数组形参的定义
以下的三种方式都是可以的,都是需要传递数组的长度的;
不管是int intArr[6]还是int intArr[]都不会创建一个数组出来,编译器也不会为它们分配内存,实际的数组是不存在的,它们最终还是会转换为int *intArr这样的指针。
int intArr[6]这种形式只能说明函数期望用户传递的数组有 6 个元素,并不意味着数组只能有 6 个元素,真正传递的数组可以有少于或多于 6 个的元素。
需要强调的是,不管使用哪种方式传递数组,都不能在函数内部求得数组长度,因为 intArr 仅仅是一个指针,而不是真正的数组,所以必须要额外增加一个参数来传递数组长度。
//int max(int intArr[], int len){
//int max(int intArr[6], int len){
int max(int *intArr, int len) {
int i, maxValue = intArr[0]; //假设第0个元素是最大值
for (i = 1; i < len; i++) {
if (maxValue < intArr[i]) {
maxValue = intArr[i];
}
}
return maxValue;
}
函数传参本质上是一次赋值的过程,赋值就是对内存进行拷贝。所谓内存拷贝,是指将一块内存上的数据复制到另一块内存上。
对于像 int、float、char 等基本类型的数据,它们占用的内存往往只有几个字节,对它们进行内存拷贝非常快速。
而数组是一系列数据的集合,数据的数量没有限制,可能很少,也可能成千上万,对它们进行内存拷贝有可能是一个漫长的过程,会严重拖慢程序的效率,为了防止技艺不佳的程序员写出低效的代码,C语言没有从语法上支持数据集合的直接赋值。
除了C语言,C++、Java、Python 等其它语言也禁止对大块内存进行拷贝,在底层都使用类似指针的方式来实现。