C/C++ 疑难点(不断更新中……)

本文深入探讨了C++中cout与指针输出的原理,解释了指针运算顺序及输出顺序的区别,并通过实例分析了%d格式符在内存读写时的顺序与小端存储方式的关系。同时,详细解析了const关键字在指针操作中的应用,以及const成员函数的限制。最后,通过具体代码展示了如何在不同情况下改变变量值与指针指向。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、cout和 指针输出

#include <iostream>
using namespace std;
int main(){
	char s[] = "012345678", *p = s;
	cout << *p++ << *(p++) << (*p)++ << *++p << *(++p) << ++*p << ++(*p)<< endl;

	return 0;
}

cout运算是从右向左进行的,但最后输出还是从左到右。也就是说,先运算++(*p)从后向前。

(1).++*p:先运算*p,值++:P指向S[0],并把S[0]加1做为表达式的值,所以输出为1,此时S[0]=='1'
(2).++(*p):同1,先运算*p,值++:P还指向S[0](S[0]现在的值为1),并把S[0]加1做为表达式的值,所以输出为2,此时S[0]=='2'
(3).*(++p):指针p位置++,然后*取值:p指向S[1],然后取S[1]的值作为表达式的值,输出'1'
(4).*++p :同3,指针p位置++,然后*取值:P指向S[2],然后取S[2]的值作为表达式的值,输出'2'
(5).(*p)++:同1,先运算*p,值++:P还是指向S[2],取S[2]的值作为表达式的值,所以输出'2',然后S[2]的值加1,S[2]==3
(6).*(p++):先取*p的值,然后指针p位置++:P还是指向S[2](现值为3),取S[2]的值作为表达式的值,所以输出'3',然后P指向S[3]
(7).*p++ :同6,先取*p的值,然后指针p位置++:P指向S[3],取S[3]的值作为表达式的值,所以输出'3',然后P指向S[4];
结果:s数组为 "213345678",输出“3324444”

2、%d的内存读取 和 内存存储

#include <stdio.h>

int main()
{
	int i=1;
	unsigned long long x = 1;
	int n = 2147483647;
	printf("%d,%d,%d\n",x,i,n);

	printf("%d,%d,%d\n",i,n,x);

	printf("%d,%d,%d\n",i,x,n);

	return 0;
}

1,0,1
1,2147483647,1
1,1,0
请按任意键继续. . .


为什么会这样?我最开始也没想明白,我认为自己输出自己的就好了嘛!~

但是情况不是这样的,输出结果如上。分析一下原因:(个人见解,可能不对,请指出)

(1)unsigned long long 是8字节的,int是4字节的。(32位机器)

(2)%d,是不进行安全检查的,都只是去取4个字节使用。

(3)现在的X86的机器都是使用的内存小端存储的方式。这3个变量在内存中的位置如下:

0x0012FF08  cc cc cc ccff ff ff 7f  ????....
0x0012FF10  cc cc cc cc cc cc cc cc  ????????
0x0012FF18  01 00 00 00 00 00 00 00  ........
0x0012FF20  cc cc cc cc cc cc cc cc  ????????
0x0012FF28  01 00 00 00 cc cc cc cc  ....????

可以看出内存中是 从高位向低位 存放,先声明的i在最内存的高位,而且数据的低字节在低位,高字节在高位,这就是小端存储的原因。

(4)解释(3)可能与本题无关哈,就当拓展下吧。当输出(x,i,n)顺序时,通过(1)(2)可知,第一个%d其实取的是x的前4位也就是低位它的值是1;到第2个i的时候,本来应该取i的内存值,但是发现紧接着第一个%d的值的后面还有4个字节,它就取了这4个字节的数据当值,而这4个字节其实是x的高位值是0;到了第三个%d自然接着向后取到的是原本i的数据。所以输出结果是(1,0,1)。

(5)第二组和第三组,原理是一样的。第三组结果看似正确,是因为最后取的X。其实是X值失去了高位的4字节的值。只不过因为它是0,没有体现出来而已。

(6)出现这样取值的原因,还有就是 printf %d 的 运算顺序是从右向左。但输出的顺序是从左向右进行取值的


3、const和指针

int * const p = &n;		//必须先初始化
*p=20;				//OK,值可以改变
p = &n;				//ERROR,不能改变指向

const int * p1;			//可以不初始化
*p1=20;				//ERROR,值不可以改变
p1 = &n;			//OK,可以改变指向
					
int const * p2;			//可以不初始化
*p2=20;				//ERROR,值不可以改变
p2 = &n;			//OK,可以改变指向

const int * const p3 = &n;	//必须先初始化
*p3=20;				//ERROR,值不可以改变
p3 = &n;			//ERROR,不能改变指向


4、const成员函数

class A
{
private:
 int m_a;
public:
 A() : m_a(0) {}
 int getConstA() const
 {
  return m_a; //同return this->m_a;。
 }
 int GetA()
 {
  return m_a;
 }
 int setConstA(int a) const
 {
  m_a = a; //这里产生编译错误,如果把前面的成员定义int m_a;改为mutable int m_a;就可以编译通过。
 }
 int SetA(int a)
 {
  m_a = a; //同this->m_a = a;
 }
};

A a1;
const A a2;
int t;
t = a1.getConstA();
t = a1.GetA();
t = a2.getConstA();
t = a2.GetA(); //a2是const对象,调用非const成员函数产生编译错误。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值