我已经用C编写了这段代码,它适用于小输入和我能想到的所有测试用例。但是当一个大文件作为输入给出时,它会给出SIGABRT错误。有人可以解释一下它的原因吗?
#include<stdio.h>
#include<string.h>
void q_sort(char **numbers, int left, int right)
{
int l_hold, r_hold,temp;
char *pivot;
l_hold = left;
r_hold = right;
pivot = numbers[left];
while (left < right)
{
while (strcmp(numbers[right],pivot)>=0 && (left < right))
right--;
if (left != right)
{
numbers[left] = numbers[right];
left++;
}
while (strcmp(numbers[left],pivot)<0 && (left < right))
left++;
if (left != right)
{
numbers[right] = numbers[left];
right--;
}
}
numbers[left] = pivot;
temp = left;
left = l_hold;
right = r_hold;
if (left < temp)
q_sort(numbers, left, temp-1);
if (right > temp)
q_sort(numbers, temp+1, right);
}
int main()
{
int x,y,i,j;
int *arr;
char **str;
int *count;
while(1)
{
scanf("%d%d",&x,&y);
if(x==0 && y==0)break;
str =(char **)malloc(sizeof(char *)*x);
count=(int*)malloc(sizeof(int)*x);
i=0;
while(i<x)
{
str[i]=(char *)malloc(sizeof(char)*y);
scanf("%s",str[i]);
i++;
}
//sizeof(str)/sizeof(*str)
q_sort(str,0,x-1);// sizeof(str) / sizeof(char *), sizeof(char *),cmp);
i=0;
j=0;
arr=(int *)malloc(sizeof(int)*x);
while(i<x)
{
arr[j]=1;
while(i<x-1 && strcmp(str[i],str[i+1])==0)
{
i++;
arr[j]+=1;
}
j++;
i++;
}
for(i=0;i<x;i++)
{
count[i]=0;
}
i=0;
while(i<j)
{
count[arr[i]-1]++;
i++;
}
for(i=0;i<x;i++)
{
printf("%d\n",count[i]);
}
free(count);
free(arr);
for(i=0;i<x;i++)
free(str[i]);
free(str);
}
return 0;
}
答案 0 :(得分:1)
给定一个数据文件:
20 20
absinthe000001
absinthe000002
...
absinthe000020
Valgrind警告(反复):
==27941== Conditional jump or move depends on uninitialised value(s)
==27941== at 0xCB9A: strcmp (mc_replace_strmem.c:721)
==27941== by 0x100000AAB: q_sort (qs.c:16)
==27941==
我也得到大量包含1或0的行。
你的下标失控了。在您的快速排序例程中添加下标打印,以查看出现了什么问题。在您阅读数据后添加打印,以确保您的数据符合您的预期。
你说:
它适用于小输入和我能想到的所有测试用例
当我尝试:
0 20
作为输入,它行为不端:
==28056==
==28056== Invalid read of size 8
==28056== at 0x100000A63: q_sort (qs.c:12)
==28056== Address 0x100006160 is 0 bytes after a block of size 0 alloc'd
==28056== at 0xB823: malloc (vg_replace_malloc.c:266)
==28056== by 0x100000BB7: main (qs.c:57)
==28056==
当我尝试:
1 20
absinthe000001
我得到一张1的印刷品。当我尝试:
2 20
absinthe000001
absinthe000002
我得到一个交替0和1的长流。坦率地说,我认为你没有尝试过很多案例。排序代码需要能够正确处理0,1,2行。
部分问题是,您有一个while (1)
循环,然后您不会检查scanf()
来电。
while(1)
{
scanf("%d%d",&x,&y);
错误的测试!
while (1)
{
if (scanf("%d%d", &x, &y) != 2)
break;
不要使用scanf()
;新手程序员使用得太难了。我只用了四分之一世纪的C语言编程;除了回答使用它的SO问题之外,我不使用scanf()
。我使用fgets()
来读取行,sscanf()
来解析它们;更简单,更容易正确处理,并且你会得到更好的错误报告(因为你可以报告整个错误的行,而不仅仅是在scanf()
修改它之后遗留的内容)。
char buffer[4096];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
if (sscanf(buffer, "%d%d", &x, &y) != 2)
break;
str = (char **)malloc(sizeof(char *)*x);
count = (int*)malloc(sizeof(int)*x);
for (i = 0; i < x; i++)
{
if (fgets(buffer, sizeof(buffer), stdin) != 0)
break;
str[i] = (char *)malloc(sizeof(char)*y);
if (sscanf(buffer, "%s", str[i]) != 1)
break;
}
您应该检查malloc()
来电的结果;如果他们失败了,你会得到一个分段违规或类似的东西。可以说,您应该创建一个格式字符串,以防止在将数据读入str[i]
时出现溢出。