C语言 在 Windows 上工作的 Linux 上的分段错误



该程序的目标是扫描一个填充有数字和空格的字符串,并将每个数字插入到数组中。然后,数组中的每个数字都被发送到checkPowerOfTwo函数,该函数确定发送的数字是否是 2 的幂并打印计算结果。

当我在Windows上运行此程序时,一切正常。在 Linux 上运行会导致分段错误。

我正在使用 Linux 服务器编译我的代码:gcc -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c -o mtm_tot.它编译成功,没有错误或警告。当我尝试运行测试器时出现问题:./mtm_tot< test1.in > tmpout.在此行上按回车键后,Segmentation fault上升。

test1.in contains : 8
5 9 -1 4 20 256 -32 17 32

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int checkPowerOfTwo(int x);
int main()
{
int exp,size,sum=0,*numbers;
char term,*str=NULL,*token;
printf("Enter size of input:n");
if(scanf("%d%c", &size, &term) != 2 || term != 'n'){
printf("Invalid Sizen");
return 0;
} if(size<=0){
printf("Invalid sizen");
return 0;
} else{
numbers=(int*)malloc(size * sizeof(int));
str=(char*)malloc(sizeof(int)*(size+1) + (size-1)*sizeof(char));
if(numbers==NULL||str==NULL){
printf("Out of memoryn");
return 0;
} //else{
//printf("Memory allocatedn");
//}
printf("Enter numbers:");
fgets (str, sizeof(int)*(size+1) + (size-1), stdin);
//printf("%s",str);
token=strtok(str," ");
while(token!=NULL){
for(int i=0;i<size;i++){
//printf("token is %sn",token);
//numbers[i]=token;
sscanf(token,"%d",&numbers[i]);
//printf("Inserting %s to the arrayn ",numbers[i]);
token=strtok(NULL," ");
}
}
}
for(int j =0;j<size;j++)
{
//sscanf(numbers[j],"%d",&x);
//printf("the number im sending is : %d ",x);
exp=checkPowerOfTwo(numbers[j]);
if (exp>=0){
printf("The number %d is a power of 2: %d=2^%dn",numbers[j],numbers[j],exp);
sum+=exp;
}
}
printf("Total exponent sum is %d",sum);
free(numbers);
free(str);
}
int checkPowerOfTwo(int x)
{
int exponent=0;
//sscanf(n,"%d",&x);
//printf("checking number %dn",x);
if (x==0){
return -1;
} if  (x==1){
return 0;
}
while( x != 1)
{
if(x % 2 != 0){
return -1;
}
x /= 2;
exponent++;
}
return exponent;
}

使用问题中所示的输入文件test1.in,您指定大小为 8 并提供 9 个数字。

您的代码

while(token!=NULL){
for(int i=0;i<size;i++){
//printf("token is %sn",token);
//numbers[i]=token;
sscanf(token,"%d",&numbers[i]);
//printf("Inserting %s to the arrayn ",numbers[i]);
token=strtok(NULL," ");
}
}

将进入外while循环,并在内for循环的第一次运行中处理 8 个数字。 当您输入 9 个数字时,token将不会NULL,外部循环将重复并再次运行内部循环。这将部分覆盖数组中的数字。在第一个周期中处理第 9 个数字后,token将变得NULL,在第 2 个周期中,sscanf将尝试使用可能导致分割错误的NULL指针。

您应该在循环条件中组合计数器和检查NULL。 我还建议检查sscanf的返回值,因为值!= 1将指示无效输入。

for(int i=0; (i<size) && (token!=NULL); i++) {
if(sscanf(token,"%d",&numbers[i]) != 1) {
/* invalid input */
break;
}
token=strtok(NULL," ");
}

当然,循环后面的代码必须处理循环以i < size结尾的情况(如果没有足够的值)。

编辑:下面的其他说明

注意:scanf的错误检查不完整。如果它无法转换整数,它将返回0,但如果它转换了一个整数并且任何内容都跟随它,它也将返回1,例如,对于123abc它将转换123并返回1。要检查数字后面可能的内容,您可以添加%c转换,如果返回值2请检查转换后的字符。('n''r'在这里可能没问题。

我更喜欢在循环中使用strtol来解析str中的数字。

顺便说一句:分配str的大小计算是错误的。sizeof int是许多系统上 4(4 字节 = 32 位)的int值的内部二进制表示的大小。它与数字的字符串表示形式需要多少个字符无关。有效的数字-2147483648需要 11 个字符。

(如果将剩余数据移动到开头并在数字之后附加新数据,直到读取终止换行符,则可以使用缓冲区str该缓冲区对于整行来说太小,但对于超过有效数字来说足够大。

你的程序逻辑是错误的:

for (int i = 0; i < size; i++) {
sscanf(token, "%d", &numbers[i]);
token = strtok(NULL, " ");
// token may become NULL here
// and sscanf will segfault right after
}

不过可能还有其他问题。

相关内容

  • 没有找到相关文章

最新更新