【QIUC】第一卷-CC++高级(九)- 由动态内存出现的问题引发的思考

【QIUC】第一卷-C/C++高级(九)-由动态内存出现的问题引发的思考

对*p++的出现的问题的思考

在内存的动态分配的学习时遇到如下问题,最初的代码是这样的,当然结果是对的:

int main1(void) {
    
    
	int farmer[6] = {
    
     20, 22, 25, 19, 18, 23  };
	int* p = new int[3];
    
	for (int i = 0; i < 3; i++) {
    
    
		*(p + i) = farmer[i];
    }
		
	for (int j = 0; j < 3; j++) {
    
    
        cout<<*(p+j)<<" ";
    }	
    
    cout<<endl;
	delete []p;
    
    system("pause");
    return 0;
}    
//输出的结果是:20 22 25

1. 使用*p++

在写到这里,我想是否可以用后置加加的方式来完成赋值这个过程,于是:

int main() {
    
    
	int farmer[6] = {
    
     20, 22, 25, 19, 18, 23 };
	int* p = new int[3];

    memset(p, 0, 3 * sizeof(int));
	for (int i = 0; i < 3; i++) {
    
    
        cout << "------对p操作前------" << endl;
        cout << p << endl;
		cout << *p << endl;
        
		*p++ = farmer[i];
        
        cout << "------对p操作后------" << endl;
        cout << p << endl;
		cout << *p << endl;
        
		cout << endl;
        cout << endl;
	}

	//delete[]p;


	system("pause");
	return 0; 
}

//没有delete[]p 的话  只是打印出的值是随机的
//若有delete[]p ,则程序直接终止

//注释delete[]p,结果是
/*
------对p操作前------
00D1CBA8
0
------对p操作后------
00D1CBAC
0

------对p操作前------
00D1CBAC
0
------对p操作后------
00D1CBB0
0

------对p操作前------
00D1CBB0
0
------对p操作后------
00D1CBB4
-33686019  这里已经指向分配的内存外部了,所以是随机值
*/

上面出现的问题是由于,此时p地址经过后置++的作用已经是指向另外的地址了,不再指向原来分配的内存的地址,所以这里的释放的地址不再是对应的,这是非常危险的

2. 不使用动态分配内存

于是,我就在想,那直接定义一个数组来分配内存会怎样

int main() {
    
    
	int farmer[6] = {
    
     20, 22, 25, 19, 18, 23 };

	

	int a[3] = {
    
     0 };
	int* p = NULL;
	p = a;
	memset(p, 0, 3 * sizeof(int));
	for (int i = 0; i < 3; i++) {
    
    
		cout << "------对p操作前------" << endl;
		cout << p << endl;
		cout << *p << endl;

		*p++ = farmer[i];

		cout << "------对p操作后------" << endl;
		cout << p << endl;
		cout << *p << endl;

		cout << endl;
		cout << endl;
	}
	
	system("pause");
	return 0; 
}
/*

------对p操作前------
010FF8D4
0
------对p操作后------
010FF8D8
0


------对p操作前------
010FF8D8
0
------对p操作后------
010FF8DC
0


------对p操作前------
010FF8DC
0
------对p操作后------
010FF8E0
-858993460
//这个地址已经越界,不属于定义的数组的元素,所以下面的访问是非法的
//所以数是一个随机数
	*/

3. 修改正确后

这样还是不行,但是当把对p操作后的*p改为 *(p-1),得到的结果完全正确,在这里,需要注意的是当 *p++ = farmer[i];执行完的时候,当farmer[i] 的地址已然被赋值了,赋值完成的一瞬间就将p的地址给加1了,此时如果再用下面的代码对p解引,显示的自然是初始化的值,而要通过 *(p-1)才能够正确访问。(感觉写这种代码就是自己给自己找麻烦)

代码如下:

int main() {
    
    
	int farmer[6] = {
    
     20, 22, 25, 19, 18, 23 };

	/*int* p = new int[3];*/

	int a[3] = {
    
     0 };
	int* p = NULL;
	p = a;
	memset(p, 0, 3 * sizeof(int));
	for (int i = 0; i < 3; i++) {
    
    
		cout << "------对p操作前------" << endl;
		cout << p << endl;
		cout << *p << endl;

		*p++ = farmer[i];

		cout << "------对p操作后------" << endl;
		cout << p << endl;
		cout << *(p - 1) << endl;

		cout << endl;
		cout << endl;
	}
	/*
------对p操作前------
008FF890
0
------对p操作后------
008FF894
20


------对p操作前------
008FF894
0
------对p操作后------
008FF898
22


------对p操作前------
008FF898
0
------对p操作后------
008FF89C
25
	
	*/

与*p++有关的C语言语法

int main3() {
    
    
	int a[5] = {
    
     0,1,2,3,4 };
	int* p = a;
	//cout << *p++ << endl;//输出是0,证明是先进行*p然后输出,
    
	//cout << *(p++) << endl;//输出是0,证明是先进行*p然后输出,其实是一样的
    
	//cout << *++p << endl;//输出是1,证明是先进行++然后输出,
    
	//cout << ++(*p) << endl;//输出是1,但是先计算的是*p,然后整个式子再加上1作为表达式的值,最后输出
    
	//cout << (*p)++ << endl;//输出是0,证明是先进行*p然后输出,最后++
	
	return 0;
}

综上所述:

*(p++) 和 *p++ 一样,都是先进行解引,再对其指向的地址进行改变

++(*p) 和 *++p 一样,都是先对其指向的地址进行改变,再进行解引

对*p++拓展

//字符转置函数(中文也可以实现)
int len = strlen((char*)s);
	unsigned char tmp[1024];

	unsigned char* p1 = s;
	unsigned char* p2 = tmp + len;

	*p2-- = 0;

while (*p1) {
    
    //临界条件使结束符0
		if (*p1 < 0x80) {
    
    
			*p2-- = *p1++;
		}
		else {
    
    
			*(p2 - 1) = *p1++;
			*p2 = *p1++;
			p2 -= 2;
		}

	}
/*
if (*p1 < 0x80) {
    *p2-- = *p1++;
}

对于这串代码出现的表达式,实际上是当临界值出现时p2的指向不合法和p1指向字符串结束符是同时的,此时进行判断,然后退出循环
*/

猜你喜欢

转载自blog.csdn.net/qq_51672565/article/details/114855970