我正在研究一些C++,我正在用指针进行斗争.我明白通过声明我可以有3个级别的指针:
int *(*x)[5];
Run Code Online (Sandbox Code Playgroud)
所以这*x是一个指向5个指向的元素数组的指针int.我也知道x[0] = *(x+0);,x[1] = *(x+1)等等....
那么,鉴于上述声明,为什么x[0] != x[0][0] != x[0][0][0]呢?
这可能是常见和微不足道的事情,但我似乎无法找到具体的答案.在C#中有一个委托的概念,它与C++中的函数指针的思想密切相关.Java中是否有类似的功能?鉴于指针有点缺席,最好的方法是什么?要说清楚,我们在这里谈论头等舱.
我不是在讨论指向const值的指针,而是指向const指针本身.
我正在学习C和C++,超越了基本的东西,直到今天我才意识到指针是通过值传递给函数的,这是有道理的.这意味着在函数内部,我可以使复制的指针指向其他值,而不会影响来自调用者的原始指针.
那么有一个函数头是什么意思:
void foo(int* const ptr);
Run Code Online (Sandbox Code Playgroud)
在这样的函数里面你不能让ptr指向别的东西因为它是const并且你不希望它被修改,但是这样的函数:
void foo(int* ptr);
Run Code Online (Sandbox Code Playgroud)
工作也一样好!因为无论如何都会复制指针,即使您修改了副本,调用者中的指针也不会受到影响.那么const的优势是什么?
以下声明之间有什么区别?
char * const a;
const char * a;
Run Code Online (Sandbox Code Playgroud)
为了理解我写这个小程序的区别:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
char a = 'x';
char b = 'y';
char * const pc1 = &a;
const char * pc2 = &a;
printf ("Before\n");
printf ("pc1=%p\n", pc1);
printf ("*pc1=%c\n", *pc1);
printf ("pc2=%p\n", pc2);
printf ("*pc2=%c\n", *pc2);
*pc1 = b;
/* pc1 = &b; */
/* *pc2 = b; */
pc2 = &b;
printf ("\n\n");
printf ("After\n");
printf ("pc1=%p\n", pc1);
printf ("*pc1=%c\n", …Run Code Online (Sandbox Code Playgroud) 我正在按照本教程关于指针如何工作.
让我引用相关段落:
Run Code Online (Sandbox Code Playgroud)int i = 5, j = 6, k = 7; int *ip1 = &i, *ip2 = &j;现在我们可以设置
Run Code Online (Sandbox Code Playgroud)int **ipp = &ip1;并
ipp指向ip1哪些点i.*ippisip1,and**ippisi,or 5.我们可以用我们熟悉的盒子和箭头符号来说明这种情况,如下所示:
如果那时我们说
Run Code Online (Sandbox Code Playgroud)*ipp = ip2;我们已经改变了指向
ipp(即ip1)的指针以包含一个副本ip2,因此it(ip1)现在指向j:
我的问题是:为什么在第二张图片中ipp仍然指向ip1但不是ip2?
我首先要说的是,使用智能指针,你永远不必担心这一点.
以下代码有什么问题?
Foo * p = new Foo;
// (use p)
delete p;
p = NULL;
Run Code Online (Sandbox Code Playgroud)
这是由另一个问题的回答和评论引发的.Neil Butterworth的一条评论产生了一些赞成:
在删除后将指针设置为NULL不是C++中的通用优良做法.有时候它是一件好事,有时它是毫无意义的,可以隐藏错误.
有很多情况下它无济于事.但根据我的经验,它不会伤害.有人开导我.
我最近很高兴向C编程初学者解释指针并偶然发现了以下困难.如果你已经知道如何使用指针,它可能看起来似乎不是一个问题,但尝试以清醒的头脑看下面的例子:
int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);
Run Code Online (Sandbox Code Playgroud)
对于绝对的初学者来说,输出可能会令人惊讶.在第2行他/她刚刚宣布*bar为&foo,但在第4行结果显示*bar实际上是foo而不是&foo!
您可能会说,混淆源于*符号的模糊性:在第2行中,它用于声明指针.在第4行中,它用作一元运算符,它获取指针指向的值.两件不同的事,对吗?
然而,这种"解释"根本不能帮助初学者.它通过指出一个微妙的差异引入了一个新的概念.这不是教授它的正确方法.
那么,Kernighan和Ritchie是如何解释的呢?
一元运算符*是间接或解除引用运算符; 当应用于指针时,它访问指针指向的对象.[...]
指针ip的声明
int *ip用作助记符; 它说表达式*ip是一个int.变量声明的语法模仿可能出现变量的表达式的语法.
int *ip应该读作" *ip会回来int"吗?但是为什么声明后的作业不遵循这种模式?如果初学者想要初始化变量怎么办?int *ip = 1(阅读:*ip将返回a int和intis 1)将无法按预期工作.概念模型似乎并不一致.我在这里错过了什么吗?
编辑:它试图在这里总结答案.
好吧,我想我们都同意以下代码所发生的事情是未定义的,具体取决于传递的内容,
void deleteForMe(int* pointer)
{
delete[] pointer;
}
Run Code Online (Sandbox Code Playgroud)
指针可以是各种不同的东西,因此delete[]对它执行无条件是未定义的.但是,让我们假设我们确实传递了一个数组指针,
int main()
{
int* arr = new int[5];
deleteForMe(arr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,在这种情况下,指针是一个数组,谁知道这个?我的意思是,从语言/编译器的角度来看,它不知道arr数组指针是否指向单个int的指针.哎呀,它甚至不知道是否arr是动态创建的.但是,如果我做以下事情,
int main()
{
int* num = new int(1);
deleteForMe(num);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
操作系统足够聪明,只能删除一个int,而不是通过删除超出该点的其余内存来进行某种类型的"杀戮狂欢"(与strlen非\0终结字符串形成对比- 它将一直持续到它点击0).
那么他们的工作是记住这些东西吗?操作系统是否在后台保留某种类型的记录?(我的意思是,我意识到我开始这篇文章时说过发生的事情是未定义的,但事实是,'杀戮狂欢'的情况不会发生,所以因此在实际世界中有人记得.)
考虑:
char amessage[] = "now is the time";
char *pmessage = "now is the time";
Run Code Online (Sandbox Code Playgroud)
我从C编程语言第2版中读到,上述两个陈述没有做同样的事情.
我一直认为数组是一种操作指针来存储一些数据的便捷方式,但显然情况并非如此...... C中数组和指针之间的"非平凡"差异是什么?
我找到了一个计算数字平方的函数:
int p(int n) {
int a[n]; //works on C99 and above
return (&a)[n] - a;
}
Run Code Online (Sandbox Code Playgroud)
它返回n 2的值.问题是,它是如何做到的?经过一点点测试后,我发现之间是(&a)[k]和/ .这是为什么?(&a)[k+1]sizeof(a)sizeof(int)