[英]Segmentation fault on linux-working on windows
这个程序的目标是扫描一个填充了数字和它们之间的空格的字符串,并将每个数字插入到一个数组中。 然后将数组中的每个数字发送到checkPowerOfTwo
function 确定发送的数字是否为 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 Size\n");
return 0;
} if(size<=0){
printf("Invalid size\n");
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 memory\n");
return 0;
} //else{
//printf("Memory allocated\n");
//}
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 %s\n",token);
//numbers[i]=token;
sscanf(token,"%d",&numbers[i]);
//printf("Inserting %s to the array\n ",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^%d\n",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 %d\n",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 %s\n",token);
//numbers[i]=token;
sscanf(token,"%d",&numbers[i]);
//printf("Inserting %s to the array\n ",numbers[i]);
token=strtok(NULL," ");
}
}
将进入外部while
循环并在内部for
循环的第一次运行中处理 8 个数字。 由于您输入了 9 个数字,因此token
不会是NULL
,外循环将重复并再次运行内循环。 这将部分覆盖数组中的数字。 在第一个周期处理第 9 个数字后, token
将变为NULL
,在第二个周期中, 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
的错误检查是不完整的。 如果它不能转换一个 integer 数字,它将返回0
,但如果它转换一个 integer 数字并且它后面有任何东西,它也会返回1
,例如对于123abc
它将转换123
并返回1
。 要检查数字后面可能出现的内容,您可以添加%c
转换,如果返回值为2
,请检查转换后的字符。 ( '\n'
或'\r'
在这里可能没问题。)
我宁愿在循环中使用strtol
来解析str
中的数字。
顺便说一句: str
分配的大小计算是错误的。 sizeof int
是int
值的内部二进制表示的大小,在许多系统上为 4(4 字节 = 32 位)。 它与数字的字符串表示需要多少个字符无关。 有效数字-2147483648
需要 11 个字符。
(如果您将剩余的数据移到开头,并且在输入数字后将 append 新数据移动到您已读取终止的换行符,则您可以使用对于整行来说太小但对于超过有效数字的缓冲区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
}
不过可能还有其他问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.