C/C++学习笔记:那些我写过的bug(长期不定时更新)

1 C++: 内存申请出错:

1.new :

这是一个奇怪的bug,而我当时定位的错误后来证明其实并不是bug.
错误警告是“段出错”:n=1时的内存分配部分语句报错。我当时定位的是如下文:

int n;
cin>>n;
int **array=new int *[n];//报错 ,n=1时段出错 ,n<0时显然也不对
assert(array!=NULL);
for(int i=0;i<n;i++)
{
array[i]=new int [n];
asssert(array[i]!=NULL);
}

可以改为

 unsigned int n;
	cin>>n;
	//或者此处另加 assert(n>=1);
	if(n>1)
	{
		int **array=new int *[n];
		assert(array!=NULL);
		for(int i=0;i<n;i++)
		{
			array[i]=new int [n];
			asssert(array[i]!=NULL);
		}
	}
	else if(n==1)
	{
		int *array=new int [n];
	}
	else
	{
		cout<<"! ERROR:n=0";
	}
	

这真的是一个严重的、令我十分尴尬的错误。然而我今天查了下其实上面写的是没问题的,因为new int [0]new int *[1]都是正常的语法,不会报错。只要[]里面的大于等于0即可。但我当时的确是改了这个问题于是“段出错的ERROR”消失了,看来是另有原因,等以后有时间好好复现一下查一查。
下面是我这次测试的代码案例


using namespace std;
	int * array=new int[0];
	cout<<&array<<endl;	
	int *array1=new int [1];
	cout<<&array1<<endl;
	int **array2=new int*[0];
	cout<<&array2<<endl;
	int **array3=new int*[1];
	cout<<&array3<<endl;
	for (int i = 0; i < 1; i++)
	{
		array3[i]=new int [1];
	}

结果是正确的,看来我犯错了,再问题定位上出了错。
上面代码块结果是
在这里插入图片描述
另外:现在发现unsigned int n;来接受输入的值也不好,有可能会造成一些隐患(细节后补),还是应该在使用前对输入进行合法性检查。

2 依旧是内存管理

曾经看过子函数中申请空间返回的经典题目,没想到还是在这儿翻了车。
首先明确第一个概念,C语言中的函数传值,传的是参量值的复制,不是参量本身;C语言为了绕开函数传值的复制提供了指针;C++又引入了“引用”的概念。虽然这里没用到。

//错误复现
//函数目的:连接字符串,并返回长度,即模拟strcat()函数
int mystrcat(char *ptr1, char *ptr2)//错误定位于此处
{
	int len1 = strlen(*ptr1);
	int len2 = strlen(ptr2);
	char *strret = new char[len1 + len2 + 1];//另先标记一下,这样写不好,容易诱发栈溢出问题。细节后补。
	assert(strret != NULL);
	strcpy(strret, *ptr1);
	strcpy(strret + len1, ptr2); //这两句完成复制
	//delete *ptr1;planA:子函数内释放空间(后发现错误,但仍然留此以供鞭策)
	ptr1 = strret; //这是为了返回新的字符串
	return len1 + len2; //返回新字符串的长度
}

原理是老生常谈的子函数中申请的空间,其首地址在函数退出时被注销掉,空间申请完了,但索引确没有了。
为了解决这种问题,常用的方法:

1. 二级指针传参

即改写为:

int mystrcat(char **ptr1, char *ptr2)
{
int len1 = strlen(*ptr1);
	int len2 = strlen(ptr2);
	char *strret = new char[len1 + len2 + 1];
	assert(strret != NULL);
	strcpy(strret, *ptr1);
	strcpy(strret + len1, ptr2); 
	*ptr1 = strret;
return len1+len2}

外面使用时,本来是

char *str1;
char *str2;
int	new_len=mystrcat(str1,str2);

现在是

char *str1;
char *str2;
int	new_len=mystrcat(&str1,str2); //此处更改

3动态数组访问出错

其实还是申请空间的问题:
申请并输入二维动态数组之后

	//申请并输入二维数组
cout << "请输入行列数:	" << endl;
	cin >> n;
	int **array = new int *[n];
	assert(array != NULL);
	for (int i = 0; i < n; i++)
	{
		array[i] = new int[n];
		assert(array[i] != NULL);
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> array[i][j];
		}
	}`

经典的指针访问二维数组有4种方式

char **p=array;
p[i][j]//1.
*(p[i]+j)//2
*(*(p+i)+j);//3.
char *p1=&array[0][0];//4仅适用于静态数组,对动态数组适用性较低。
*(p+i*rowSize+j)
//或者
char *p1=*array;//或*p1=*array[0]
*(p+i*rowSize+j)

这里重点说一下第四种方式,对动态数组适用性较低。这是因为,二维动态数组所申请的空间一般不是完全连续的。从上面申请空间来看(其内存分布是一块一块的)
例如接上文申请的空间,显示各元素地址及内特容`

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cout <<array[i][j]<<"  "<<&array[i][j] << "   ";
		}
		cout << endl;  	 
	 }

其结果为:
显然每一行的元素都连续,不同行之间完全不连续
显然每一行的元素都连续,不同行之间不连续,这种情况下使用*(p+i*row+j)就无法正确寻址到其他行的元素。
如果铁了心要用的话,必须是

int *p=array[i];
*(p+j)//可以寻址完全不如array[i][j]方便

4 .memset使用出错

memset(void *src,int val ,unsigned long size)

其中,val虽然是int类型,但是只有低8位有效…例如

int val=0x12345678;
那么赋值之后,会变成 0x78787878;

5 .

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值