程序效果分析
需求分析
这个程序主要实现的是数组初始化、计算数组长度、数组拷贝、数组打印、插入特定位置的元素、删除元素、排序的功能,主要函数如下:
int Initarray(int *array);//初始化数组
int length(int *array);//计算数组长度
int copyarray(int *src, int *dest);//复制数组
int printarray(int *array);//打印数组
int insert(int *array, int idx, int val);//插入
int deletearray(int *array, int idx);//删除
int sort(int *array, int size);//排序
效果分析
- 输出旧数组
- 输入新数组
将会输出数组长度,以及复制成功的信息,输出复制的数组
-
对拷贝好的数组进行操作选择
-
插入操作
-
删除操作
-
排序
-
退出程序
如果不输入q,则程序不会退出,将一直进行操作。
主要程序内容分析
主函数
- 定义操作的数组,旧数组array,开辟新数组new_array,以及函数当中将会使用的变量
/******** 定义操作数组 ************/
int array[] = { 5,3,4,1,2,-9999 };
int new_array[1000]; //作用于new_array
int inumber = 0;
int dnumber = 0;
int ival;
char choice;//操作选择字符
- 输入新数组,计算数组长度,进行拷贝操作
/********* 初始化并输出数组,计算数组长度 *********/
printarray(array);
Initarray(new_array);//数组初始化,输入目标数组
copyarray(tempv, new_array);//将输入数组改为操作数组
printarray(tempv);
int n = length(tempv);//计算数组长度,并输出
system("pause");
- 选择操作,一直到输入q为止(do…while…)
/********* 选择数组操作内容 ************/
do
{
choice = Choice();/*选择算法*/
switch (choice)
{
case'i': //向数组插入新元素
cout << " ********* Inputing the Index number: ********* " << endl;
cin >> inumber;
cout << " ********* Inputing the content you want: ********* " << endl;
cin >> ival;
insert(tempv, inumber, ival);
break;
case'd': //删除数组元素
cout << " ********* Inputing the Index number: ********* " << endl;
cin >> dnumber;
deletearray(tempv, dnumber);
break;
case's'://排序
n = length(tempv);
sort(tempv, n);
break;
case'q'://退出程序
break;
}
} while (choice != 'q');
数组打印int printarray(int *array)
打印的时候遇到的主要问题还是,因为开辟的数组空间长,没有输出的限制,会导致访问越界。为此,在初始化数组的时候,以-9999作为结尾,一旦出现-9999,则停止输出,在后续长度估计也有应用。
int printarray(int *array)
{
int j = 0;
cout << " **************** The Array is: ************* " << endl;
while (array[j] != -9999)
{
cout << array[j] << "\t";
j++;
if (j % 5 == 0)cout << endl;
}
cout << endl;
return 0;
}
数组长度估计int length(int *array)
数组长度估计,主要还是注意的是-9999作为结尾,n是从0开始估计的,只要未碰到-9999,n自加1。
int length(int *array)
{
int n;
for (n = 0; array[n] != -9999; n++);
cout << endl;
cout << "The length of the array is :" << n << endl;
return (n);
}
数组初始化int Initarray(int *array)
数组初始化问题同上,开辟数组空间大,要有一个特定的结尾表示输入结束,此处建立ch标识,只要ch为回车输入,停止输入数组元素。同样,为了后续的长度估计以及输出数组操作,将结尾处设为-9999.
int Initarray(int *array) //初始化new_array
{
cout << " ******************************************************* " << endl;
cout << " *********First:You should Inpute the new array: ******* " << endl;
cout << endl;
int i = 0, j = 0;
char ch = 0;
while (ch != '\n')
{
cin >> array[i];
ch = getchar();
i++;
}
array[i] = -9999;//以-9999结束
cout << endl;
return 0;
}
数组拷贝int copyarray(int *src, int *dest)
数组拷贝遇到的问题,主要还是如果复制到的目的数组开辟空间不足够,将会遇到数组访问越界的问题,本来尝试开辟新空间,改变原数组地址等方法,但不了了之,还是空间够大比较好。
int copyarray(int *src, int *dest)
{
//int *change_ptr(int *ptr, int *dest);
int n = length(dest);
//int m = length(src);
//tempv = new int[n + 1];
//if (m <= n)
//{
// tempv = new int[n + 1];//定义新数组,分配空间与dest相同
//memcpy(tempv, src, m);//将旧数组复制到tempv当中
//src = tempv;//地址改为tempv
for (int i = 0; i < n+1 ; i++)
{
//*(src + i) = *(dest + i);
*(tempv + i) = *(dest + i);
//src[i] = dest[i];
}
//src = change_ptr(src,tempv);//地址改为tempv
cout << " ************* Coping is successful! ************* " << endl;
// system("pause");
return 0;
//}
/*else
{
int n = length(dest);
int m = length(src);
for (int i = 0; i < n; i++)
{
*(src + i) = *(dest + i);
}
for (int j = n; j < m; j++)
{
*(src + j) = *(dest + j);
}
}
cout << " ************* Coping the array is successful! ************* " << endl;
system("pause");
return 0;*/
}
插入int insert(int *array, int idx, int val)
思路:和删除比较相像,当数组号大于所要插入位置时,所有元素向后挪,也就是:
删除int deletearray(int *array, int idx)
思路:
- 首先要对索引号是否合法进行判断,当是在数组长度n以内、刚好接在数组后的时候是合法的。如果输入的是其他情况,则会返回-1,数组索引不合法。
- 要对数组进行删除操作,并能够传递回主函数,那么函数传递的是数组的地址。
数组进行移动的主要方法是:改变原数组指针指向。当数组大于要求删除的位置时,将把数组指向向后移动一个位置,也就是说,将利用指针向后一个指向,达到屏蔽掉对应元素。当然,在所要求的删除位置之前,不进行指向的改变。
注意:其实内存中的索引号是比我们认为的位置多1的,所以判断的时候别忘记加上1;另外,指针应该从后往前,和插入是不同的,否则,会把-9999给前一个位置,然后又给前一个位置变成-9999.
排序int sort(int *array, int size)
主要问题以及解决办法
在写的时候遇到的最大的问题还是在拷贝数组上,由于数组的静态空间导致越界、拷贝长度调整等问题,使得程序没能呈现意料中的效果。以史为鉴可以知兴衰,总结一下遇到的主要问题:
copyarray(int *src, int *dest); //将dest拷贝到src
- 开始的时候,拷贝函数还是比较简略的,是直接改变了src数组的指向,没有考虑过静态空间的问题,只要数组dest的长度大于src的长度,就会出现越界。
int copyarray(int *src, int *dest)
{
int n = length(dest);//计算dest数组长度,以便循环改变指向
for(int i = 0;i<n+1; i++)//n+1主要是因为结束是-9999,不能忽略了
{
*(src+i) = *(dest + i);
}
cout<<**** COPING THE ARRAY ************* " << endl;
printarray(src);//输出数组
system("pause");
return 0;
}
- 考虑到以上问题,为了避免越界问题,提出了以下重新分配空间的操作。(其实,这个函数实际上也不能真正拷贝数组,若dest长度大于src的时候,可以通过分配新空间,改变src指向的方法来实现,但原本src空间被摒弃。若dest长度小于src,可以说是用-9999这个标识来标志src的结束,实际上,src数组仍然有其他元素。)
- 但是,程序在运行时,只要输入的dest大于src,就会出现不复制的情况。估计是if条件出现了一些问题。
- 循环处设置断点,发现在循环前,src的内容并没有被复制到tempv,反而两者都出现乱码,未知的分配
- 回溯思路,看是否有理解偏差
首先int *tempv = new int[n+1]是为了分配新的存储空间,这个空间可以存储下dest的元素;
其次,memcpy(temp,src,m);是为了实现元素的复制,将src前m个元素全部赋值给tempv。
在这步进行操作的时候,发现根本没有把src数组值给到tempv。回头看的时候,发现src首地址根本没有发生改变,输出仍然是原数组。 - 问题出在:函数内定义的tempv在函数结束之后被释放,不能传到主函数当中!
- 解决问题的核心就是要解决地址传输的问题。我想要解决这个问题,思路如下:1.将tempv声明为全局变量,那么函数结束之后将不会释放建立好的tempv。——>2.将地址传输到主函数当中。但是这个办法是行不通的,因为,主函数中建立好的src其实是一个指针常量,没办法通过赋值的方式来改变。只能通过改变指针的指向。
- 放弃从改变地址的方向来改变,后面还是直接用全局变量tempv来复制数组了。
int copyarray(int *src, int *dest)
{
int n = length(dest);
int m = length(src);
if (m <= n)
{
int *tempv = new int[n + 1];//定义新数组,分配空间与dest相同
memcpy(tempv, src, m);//将旧数组复制到tempv当中
src = tempv;//地址改为tempv
for (int i = 0; i < n+1; i++)
{
*(src + i) = *(dest + i);
}
}
else
{
for (int i = 0; i < n; i++)
{
*(src + i) = *(dest + i);
}
for (int j = n; j < m; j++)
{
*(src + j) = *(dest + j);
}
}
cout << " ************* COPING THE ARRAY ************* " << endl;
printarray(src);//输出数组
system("pause");
return 0;
}
总结
总的来说,问题有以下几种:
- 基础知识:数组的理解不够透彻,编程思路不够清晰上面,在初步思考的时候,应该就要把一些可能有的问题写下来,然后在写代码的过程中考虑进去。
- 对于指针类容易出错的问题,可以在其中加入cout,打印出。只要是可能出现问题的地方
都可以加入cout,进行一个问题回溯。 - 写完函数之后,对于每个函数的功能要进行一个彻底的检查,以免出现牵一发动全身的错误。