我总是搞砸如何正确使用const int*、const int*const和int const*。有没有一套规则来定义你能做什么和不能做什么?
我想知道在赋值、传递给函数等方面的所有注意事项。
我总是搞砸如何正确使用const int*、const int*const和int const*。有没有一套规则来定义你能做什么和不能做什么?
我想知道在赋值、传递给函数等方面的所有注意事项。
当前回答
我想这里已经回答了所有问题,但我只想补充一点,你应该小心typedefs!它们不仅仅是文本替换。
例如:
typedef char *ASTRING;
const ASTRING astring;
跨接的类型是char*const,而不是const char*。这是我总是倾向于将常量放在类型的右边,而从不放在开头的原因之一。
其他回答
这主要涉及第二行:最佳实践、分配、功能参数等。
一般做法。尽可能使一切保持稳定。或者换一种说法,从一开始就让所有的常量都是常量,然后完全删除允许程序运行所需的最小常量集。这将大大有助于实现常量正确性,并有助于确保在人们尝试分配不应该修改的内容时不会引入细微的错误。
避免像瘟疫一样的const_cast<>。它有一两个合法的使用案例,但它们非常少。如果你试图改变一个常量对象,你会做得更好,找到第一步中声明它常量的人,并与他们讨论此事,以就应该发生的事情达成共识。
这很好地引导到作业中。只有当它是非常量时,才能将其赋值。如果您想分配给常量,请参见上文。请记住,在声明中int const*foo;和int*const bar;不同的东西是恒定的——这里的其他答案都很好地涵盖了这个问题,所以我就不赘述了。
功能参数:
传递值:例如,voidfunc(int-param),在调用站点,你不在乎这一种方式或另一种方式。可以这样做,即存在将函数声明为void func(int const param)的用例,但这对调用方没有影响,只对函数本身没有影响,因为函数在调用期间不能更改传递的任何值。
通过引用传递:例如,void func(int¶m)现在它确实起了作用。正如刚才声明的,func可以更改参数,任何调用站点都应该准备好处理结果。将声明更改为void func(int const¶m)将更改约定,并保证func现在不能更改param,这意味着传入的内容将返回。正如其他人所指出的,这对于便宜地传递不想更改的大型对象非常有用。传递引用比按值传递大型对象要便宜得多。
传递指针:例如,void func(int*param)和void func(int const*param)这两个与它们的引用对应项几乎同义,但需要注意的是,被调用的函数现在需要检查nullptr,除非其他契约保证func不会在param中收到nullpter。
关于这个话题的评论文章。在这种情况下证明正确性非常困难,犯错误太容易了。所以不要冒险,总是检查指针参数的nullptr。从长远来看,你会让自己免于痛苦和痛苦,并且很难找到bug。至于检查的成本,它非常便宜,在编译器中内置的静态分析可以管理它的情况下,优化器无论如何都会取消它。为MSVC启用“链接时间代码生成”,或为GCC启用“WOPR(我认为)”,您将在程序范围内获得它,即即使在跨越源代码模块边界的函数调用中。
在一天结束时,以上所有内容都证明了一个非常可靠的理由,即总是倾向于引用指针。他们只是更安全。
反向阅读(由顺时针/螺旋法则驱动):
int*-指向int的指针int const*-指向const int的指针int*const-指向int的const指针int const*const-指向const int的const指针
现在,第一个常量可以位于类型的任一侧,因此:
常量int*==int常量*const int*const==int const*const
如果你想变得疯狂,你可以这样做:
int**-指向int指针的指针int**const-指向int指针的const指针int*const*-指向int的const指针int const**-指向常量int的指针int*const*const-指向int的常量指针的常量指针...
为了确保我们清楚const的含义:
int a = 5, b = 10, c = 15;
const int* foo; // pointer to constant int.
foo = &a; // assignment to where foo points to.
/* dummy statement*/
*foo = 6; // the value of a can´t get changed through the pointer.
foo = &b; // the pointer foo can be changed.
int *const bar = &c; // constant pointer to int
// note, you actually need to set the pointer
// here because you can't change it later ;)
*bar = 16; // the value of c can be changed through the pointer.
/* dummy statement*/
bar = &a; // not possible because bar is a constant pointer.
foo是指向常量整数的变量指针。这允许您更改指向的内容,但不更改指向的值。最常见的情况是,C样式字符串中有一个指向常量字符的指针。您可以更改指向的字符串,但不能更改这些字符串的内容。当字符串本身位于程序的数据段中且不应更改时,这一点很重要。
bar是指向可更改值的常量或固定指针。这就像没有额外语法糖的引用。由于这一事实,通常您会在使用T*常量指针的地方使用引用,除非您需要允许NULL指针。
对于那些不了解顺时针/螺旋规律的人:从变量的名称开始,顺时针移动(在这种情况下,向后移动)到下一个指针或类型。重复此操作,直到表达式结束。
下面是一个演示:
为了C遵循其他解释的完整性,对C++不确定。
pp-指针到指针p-指针数据-在示例x中指出的内容粗体-只读变量
指针
p数据-int*p;p数据-int常量*p;p数据-int*const p;p数据-int const*const p;
指向指针的指针
pp p数据-int**pp;pp p数据-int**const pp;pp p数据-int*const*pp;pp p数据-int常量**pp;pp p数据-int*const*const pp;pp p数据-int const**const pp;pp p数据-int const*const*pp;pp p数据-int常量*常量*常量pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
N级取消引用
继续前进,但愿人类将你逐出教会。
int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;
printf("%d \n", ****pppp);
对我来说,常量的位置,即它相对于*是出现在左侧还是右侧,还是同时出现在左侧和右侧,有助于我理解实际含义。
*左边的常量表示指针指向的对象是常量对象。*右边的常量表示指针是常量指针。
下表摘自斯坦福CS106L标准C++编程实验室课程阅读器。