惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
M
MIT News - Artificial intelligence
G
Google Developers Blog
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
MyScale Blog
MyScale Blog
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
爱范儿
爱范儿
罗磊的独立博客
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
Vercel News
Vercel News
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog
C
Check Point Blog
美团技术团队
宝玉的分享
宝玉的分享
Microsoft Security Blog
Microsoft Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

博客园 - 新西兰程序员

C++ 构造函数中的初始化参数列表initializer list C++中的线程thread,以及C++11中的std::atomic学习 Leetcode56 Merge Intervals 合并区间 -- C++实现 C++中的内存对齐 C++中的static关键字使用以及全局变量 C++17中的结构化绑定Structured Binding C++中异常处理机制中的栈展开stack unwinding C++实现链表反转 Linux中的性能分析工具 perf 来分析C++性能 C++17中新建一个类时,编译器默认生成的类成员函数 QT中的元对象系统 Leetcode 114 - 二叉树展开为链表 Leetcode65 有效数字 - 判断给定的字符串是否是一个有效数字 LettCode2289-Steps to Make Array Non-descreasing C#中的委托详解 C++中的std::function C++中的仿函数Functor C++中的const和constexpr异同比较 C++中的左值和右值,以及右值引用,移动语义 C++中传递参数是指针类型以及传入参数是指针的指针(**)详解 C++中GetTickCount函数学习 C++中以类的成员函数作为Windows callback函数需要设置成static函数 C#中的System.Security.SecureString学习 C++中的悬挂指针和野指针 C++中四种不同的对象生存方式(in stack, in heap, global, local static) C#中使用Parallel类来进行多线程并发编程 String类型转LPCTSTR -----理解C++中的字符串类型转换 C++中的虚函数和虚函数表 C++中基类指针指向派生类对象 数据结构 - 栈的学习
C++中的函数参数是指针类型, 是按值传递
新西兰程序员 · 2026-04-24 · via 博客园 - 新西兰程序员

我们来看C++中函数中传入的参数是指针类型的情况, 我们来看一个例子

#include <iostream>
int main()
{
int
* p = new int(10);
testFunc(p);
std::cout << *p << endl; //这里输出的是15

}

void testFunc(int* p) { *p = 15; }

 首先我们来看 上面中的 testFunc(int* p) => 它的参数是指针类型,C++中传入的参数是指针类型,那么就意味着传入的是地址,我们来看下面这个例子

void swap(int* x, int* y)
{
    int temp = *x;
    *x = *y;
    *y = temp;
}


int main()
{
     int a = 9, b;

     swap(&a, &b); //这里传入的是整形数a,b的地址

    std::cout << *a << "   " << *b <<end1;
}

从上面这个例子中可以看出,swap函数的形参是指针类型,在调用它的时候,传入的就是参数的地址

现在,我们再回来看最上面的例子: 

int* p = new int(10);  => new int(10) 这句话,是用C++的关键字来在内存中开辟了一块内存,这块内存中存的是整形数据10,它返回的是一个int型的指针,这个指针指向这块内存的地址.
当我调用 testFunc函数时,传入的是参数的地址,所以是 testFunc(p) => 这里要好好理解,它这里是按值传递的,也就是说,这里,在函数testFunc内部,它会把指针p复制一份,产生一个新的指针(我们可以叫 new p),只不过这个新的指针new p和原来的指针p都同时指向同一块内存

image

 我们再来看上面第一个例子

 
 int* p = new int(10); //指针p 指向关键字new分配的内存(我们叫它 内存A),这块内存中存的是整数值 10
testFunc(p); // 在testFunc函数内产生一个新的指针Copy p, 它指向的也是内存A,在它内部,把内存A存的整数值改成了15
所以,例子中输出的是15

现在,我们再来看一道经典的面试题

void foo(int* p)
{
   p = 0; // 这里是把p设置为空指针,也就是说不指向任何有效的内存. 它等价于 p = NULL 或者 p = nullptr, 但从C++11开始,推荐用nullptr
}

int main()
{
   int* p = new int(20);
   foo(p);
   std::cout << p[0] << std::endl;
}

上面代码输出什么  => 输出20, 因为foo(p) 函数里面只是复制了一份新的指针p, p=0 只是把复制的这份新指针变为空指针,但是main函数中原来的指针p还是一样存在,还是指向那块存了20的内存,所以输出还是20

但是上面的foo函数内部是有问题的,在p=0把指针p设置为空指针(不指向任何内存的指针)之前,应该把它指向的内存删除释放出来,所以,之前需要 delete p;

这里,理解一下p[0], 为什么可以这样写? => 是可以这样写的,这里涉及到一个概念

在内置类型(数组 / 指针)上,[] 本质就是“指针偏移 + 解引用”的语法糖  => 这句话怎么理解呢,也就是说对于内置类型,a[b] = *(a+b)

int arr[3] = {10,20,30};

int x = arr[1];  这句话在这里等价于 int x = *(arr + 1); // 但千万注意,不是 x = *arr1 
也就是说,
arr[0] 等价于 *(arr + 0),但不是 *arr0
arr[1] 等价于 *(arr + 1),但不是 *arr1

arr[2] 等价于 *(arr + 2),但不是 *arr2

因为 *arr0,*arr1,*arr2三个指针压根就不存在的

所以,上面的 int * p = new(20); p[0] 就等价于 *(p + 0), 也就是 *p, 所以输出的是20  => 但是我们是完全不推荐这么写的, 虽然在这个例子中p[0]没有越界(因为就算第0个元素),但是这会暗示它是个数组,给人造成误解,因为这里显然它不是数组. 而且,如果这里代码编写人员误写p[1], 那就造成了越界访问,产生未定义的行为错误.

但是注意到没有,我们上面特意强调了,在内置类型上. 如果不是内置类型,是自定义类型,比如重载运算符operator[], 它就不是“指针偏移+解引用”了, 也不能这么用了

struct MyArray
{ 
   int arrData[3] = {1,2,3};  
int& operator[](int i)
{
std::cout << "output data in position " << i +1 <<endl;
if(0 <= i < arrData.size()-1)
return arrData[i+1];
else
return arrData[0];
} }

 上面这个例子中,我们用operator关键字重写了[], 当数组中坐标是i时,我们输出的不是arrData[i]的值,而是arrData[i+1];

在这里

MyArray a;
a[1]; //调用的是operator[]

这里的a[1], 它就不等于 *(a+1)

 
好了,我们来看C++中一个非常经典的面试题目
int arr[3] = {10, 20, 30};
int* p = arr;

std::cout << sizeof(arr) << std::endl;
std::cout << sizeof(p) << std::endl;

我们假设系统中int是占4个字节,指针占8个字节(64位系统),那么上面输出的是什么

sizeof(arr)输出的是12  => 输出的数组占的内存大小 4 * 3 = 12

sizeof(p)输出的是8  => 输出的是p这个指针占的内存大小

这里涉及到一个概念 - 数组退化

数组退化 => 大多数情况下,arr都会退化成指针int*(指向数组首元素),但是sizeof是少数不会退化的场景,所以sizeof(arr)它获取的是数组的整块内存
我们再来看一个经典的坑
#include <iostream>
void foo(int arr[]) {
    std::cout << sizeof(arr) << std::endl;
}

int main()
{
   int arr[3] = {10, 20, 30};
   foo(arr); // 这里输出的是什么?
}

 在64位系统中,这里输出的是指针大小8(32位系统是4) => 因为数组名作为函数参数时(arr作为函数foo的参数),数组名会退化为指针,所以,这里在函数foo内部,sizeof(arr)返回的是指针大小,而不是数组大小