幫别人調試個程式,程式的功能主要涉及動态數組,實作動态數組元素的添加,删除,查找,顯示功能。但是在執行添加功能的時候,連續執行三次添加的時候就會出現問題,讓人感到非常的莫名其妙。
涉及到的函數如下所示:
void adddata(int * arr, int * len)
{
int n;
int *add;
int cnt=0, t1;
printf("pleaseenter the amount of element you want to add;\n");
scanf("%d",&n);
add = (int*)malloc(sizeof(int)* n);
inputdata(add, n); //把使用者要添加的資料加入一個新的數組。
t1 = *len; //下面循環有用,當使用者輸入的數都大于任何數的時候用的
*len = *len + n ; //重新定義下數組長度,根據使用者要擴充的大小。
realloc(arr, sizeof(int)*(*len));
for (i=0;i<n; ++i) // i 循環是循環要添加的數
{
for(j=0; j<t1+i; ++j) // j循環是循環原數組
{
if( add[i] < arr[j])
{
for (k=j; k <= t1+i; ++k)
{
t =arr[k];
arr[k]= add[i];
add[i]= t;
}
cnt = 1;
break;
}
cnt = 0;
}
if( 0 == cnt)
arr[t1+i]=add[i];
}
resultdata(arr, *len);
switch_choice (arr, * len);
}
從這裡可以看到這段程式的缺點:
<1>全局變量的濫用,不過這裡沒有造成錯誤
<2>realloc函數不适用傳回值,後面會知道這是罪魁禍首
<3>malloc的add沒有在函數結束的時候釋放
1 針對函數的缺點,我們一一偵破,先是在函數的結尾加上對add的釋放
if(add != NULL)
{
free(add);
add = NULL;
}
但是第一次釋放add就會出現下面的問題,執行調試,發現是在free的時候出現了問題,也就是free竟然失敗了。
2 然後再加上對realloc函數的修改
void *realloc(void *memblock, size_t size );
Realloc函數會針對不同的情況執行不同的行為,如果realloc函數執行成功,那麼函數會傳回新的記憶體空間的首位址,并且free掉之前 的記憶體空間,并且之前的記憶體内容複制到新的記憶體中;如果開辟失敗,那麼之前的記憶體空間不會被釋放,realloc函數傳回NULL。是以在增加記憶體的時候,萬萬不可使用一直使用原來的全局指針,原因就是它可能已經被free掉,而新的指針指向發生了變化。
同時如果繼續使用原來的全局指針,就可能發生數組的越界,越界就會破壞堆,最終連其它的跟操作記憶體的函數執行都會出現問題。
現在把void adddata(int * arr,int * len)
中的realloc函數修改成如下:
tmp = (int*)realloc(arr, sizeof(int)*(*len));
if( tmp!= NULL)
{
arr = tmp;
tmp = NULL;
}
else
{
printf("reallocmemory failed\n");
exit(1);
}
然後測試,一切OK,這說明了罪魁禍首的确是realloc函數的錯誤使用,realloc不會保證新記憶體的首位址還是原來的,它很可能發生變化。
3 針對realloc函數錯誤調用後,發生數組越界會造成free失敗的驗證
測試代碼如下所示:
#include <stdio.h>
#include <stdlib.h>
void main()
{
int n = 3;
int na;
int i;
int *p2;
int *p = (int*)malloc(sizeof(int)*n);
int *p3 = ( int*)malloc(sizeof(int)*3 );
p3[0] = 11;
p3[1] = 22;
p3[2] = 33;
for(i=0;i<n;i++)
{
p[i] = i;
}
for(i=0;i<n;i++)
printf("%d\n",p[i]);
printf("input mount of number to add:");
scanf("%d",&na);
p2 = (int*)realloc( p,sizeof(int)*(n+na) );
for(i=n;i<n+na;i++)
{
p2[i] = i;
}
p[n+na+ 10] = 0; // out range of p
for(i=0;i<n+na;i++)
printf("%d\n",p2[i]);
printf("now can see\n");
for(i=0;i<n;i++)
printf("%d\n",p[i]);
if( p3 != NULL) //failed because of p's outof range
{
free(p3);
p3 = NULL;
}
}
執行結果:
這個就說明了一切問題,p的越界造成了無辜的p3跟着遭殃,p3到最後都不能進行釋放。
附錄(修改後的完整的功能程式):
#include <stdio.h>
#include <stdlib.h>
void inputdata( int * arr, int len);
void arrangeinorder( int * arr, int len);
void resultdata(int*, int);
void switch_choice(int * , int );
void finddata( int * arr, int len);
void deletedata(int * arr, int * len);
void adddata(int * arr, int * len);
int main (void)
{
int *arr;
int len;
printf ("enter the amount of data that you will input: ");
scanf("%d", &len);
arr = (int *) malloc( sizeof(int) * len);
inputdata(arr, len); //單獨測試可用(用來輸入數組)
arrangeinorder(arr, len); // 單獨測試可用(把數組進行排序,從小到大)
switch_choice (arr, len);
free(arr);
return 0;
}
void inputdata( int * arr, int len)
{
int i;
printf("please enter your data ;\n");
for (i=0; i<len; ++i)
{
printf("%d--> ", i+1);
scanf("%d", &arr[i]);
}
}
void arrangeinorder( int * arr, int len)
{
int i,j,t;
for (i=0; i<len; ++i)
{
for (j=i+1; j<len; ++j)
{
if (arr[i] > arr[j])
{
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
}
resultdata(arr, len);
}
void finddata( int * arr, int len)
{
int n,i;
int t = 0;
printf("please enter the number you want to find\n");
scanf("%d", &n);
for (i=0; i<len; ++i)
{
if (n == arr[i])
{
printf ("the number %d, is located in the %d th\n", n,i+1);
t=1;
}
}
if (t != 1 )
printf("number %d is not in this array.\n", n);
}
void deletedata(int * arr, int * len)
{
int n,i,j;
int cnt =0;
printf("please enter the number you want to delete from this array;\n");
scanf ("%d", &n);
for (i=0; i<*len; ++i)
{
while(n == arr[i])
{
for (j=i; j<*len; ++j)
arr[j] = arr[j+1];
cnt++; //to count amount of number had been delete from array.
}
}
*len = *len - cnt;
arr = (int*)realloc(arr, sizeof(int)*(*len));
if( arr == NULL )
{
printf("realloc memory failed\n");
exit(1);
}
resultdata(arr, *len);
switch_choice (arr, * len);
}
void adddata(int * arr, int * len)
{
int n,i,j,k,t1;
int *add,*tmp;
int cnt =0;
int t = 0;
printf("please enter the amount of element you want to add;\n");
scanf("%d", &n);
add = (int *)malloc(sizeof(int) * n);
inputdata(add, n); //把使用者要添加的資料加入一個新的數組。
t1 = *len; //下面循環有用,當使用者輸入的數都大于任何數的時候用的
*len = *len + n ; //重新定義下數組長度,根據使用者要擴充的大小。
//realloc(arr, sizeof(int)*(*len));
tmp = (int*)realloc(arr, sizeof(int)*(*len));
if( tmp != NULL)
{
arr = tmp;
tmp = NULL;
}
else
{
printf("realloc memory failed\n");
exit(1);
}
for (i=0; i<n; ++i) // i 循環是 循環要添加的數
{
for (j=0; j<t1+i; ++j) // j循環 是循環原數組
{
if ( add[i] < arr[j])
{
for (k=j; k <= t1+i; ++k)
{
t = arr[k];
arr[k] = add[i];
add[i] = t;
}
cnt = 1;
break;
}
cnt = 0;
}
if ( 0 == cnt)
arr[t1+i]=add[i];
}
if (add != NULL)
{
free(add);
add = NULL;
}
resultdata(arr, *len);
switch_choice (arr, * len);
}
void resultdata( int * arr, int len)
{
int i;
printf("new array has been show below\n");
for ( i=0 ; i <len ; ++i)
{
printf("%d--> ", i+1);
printf("%2d \n", arr[i]);
}
}
void switch_choice(int * arr, int len)
{
int n;
printf("type number to choose the function you are going to use:\n");
printf("1. activate number search.\n");
printf("2. delete number from this array. \n");
printf("3. add new numbers to this array. \n");
printf("4. exit this program. \n");
scanf("%d", &n);
switch (n)
{
case 1:
finddata (arr, len);
break;
case 2:
deletedata (arr, &len);
break;
case 3:
adddata ( arr, &len);
break;
case 4:
return;
break;
}
}