所以,我目前正在为我的Unix OS类进行系统编程。该程序应该执行的所有操作都是读取二进制文件并将行输出到CSV文件。我觉得我差不多完成了,但由于某种原因,我不断陷入错误。
澄清: fd1 =输入文件, fd2 =输出文件, numrecs =输入文件中的记录数。 在main()的某个地方:
for(i=0;i<numrecs;i++){
if((bin2csv(fd1, fd2)) == -1){
printf("Error converting data.\n");
}
}
int bin2csv(fd1, fd2){
bin_record rec;
char buffer[100];
int buflen;
strncpy(buffer,"\0", 100); /* fill buffer with NULL */
recs = &rec;
/* read in a record */
if((buflen = read(fd1, &recs, sizeof(recs))) < 0){
printf("Fatal Error: Data could not be read.\n");
return -1;
}
sprintf(buffer, "%d, %s, %s, %f, %d\n", recs->id, recs->lname, recs->fname, recs->gpa, recs->iq);
printf("%s\n", buffer);
write(fd2, buffer, sizeof(buffer));
return 0;
}
段错误发生在&#34; sprintf(缓冲区等);&#34;但是,我无法弄清楚为什么会这样。
这是gdb吐出的错误:
编程接收信号SIGSEGV,分段故障 bin2csv中的0x0000000100000c87(fd1 = 3,fd2 = 4)bin2csv.c:25
25 sprintf(缓冲区,&#34;%d,%s,%s,%f,%d \ n&#34;,recs-&gt; id,recs-&gt; lname,
recs-&gt; fname,recs-&gt; gpa,recs-&gt; iq);
希望这是足够的信息。谢谢!
答案 0 :(得分:3)
看起来recs
是一个指针。您正在将字节直接读入该指针,例如从文件中读取原始内存地址:
read(fd1, &recs, sizeof(recs))
然后你开始在调用sprintf
... BOOM!
实际上根本没有理由使用它(它是全局的吗?)......即使你用recs = &rec
初始化它,并假设你没有丢弃它,它仍然不会包含有效在该功能之外的地址。那是因为rec
是一个局部变量。
所以,请直接阅读rec
,如下所示:
read(fd1, &rec, sizeof(rec))
然后在sprintf
行,您使用rec.id
代替recs->id
( etc )。
答案 1 :(得分:2)
我在这里看到一些问题:
sprintf
不会阻止写入字符串缓冲区的末尾。实际上,它不知道该缓冲区的长度(在您的情况下为100字节)。由于您已在堆栈中设置了缓冲区,如果sprintf
过度运行缓冲区(可以使用长的名字或姓氏或垃圾字符串作为输入),您的堆栈将被破坏并且可能出现seg错误。您可能需要考虑包含逻辑以确保sprintf不会超过您拥有的缓冲区空间量。或者更好的是完全避免sprintf
(更多关于以下内容)
您没有在提供的代码中处理文件结尾。对于文件结尾,read返回0.如果您将错误的指针传递给sprintf
,它将失败。
您使用的函数是UNIX派生的函数(POSIX的一部分,但绝对是低级别),它们使用小整数作为文件描述符。我建议改用基于FILE *
的。感兴趣的I / O函数将是fopen
,fclose
,fprintf
,fwrite
等。这将消除使用sprintf
的需要。
有关详细信息,请参阅this previous question。
答案 2 :(得分:1)
Public Sub LoadImage(ByVal caseNum As String, ByVal commnum As String)
If Me.SpGetLOMCDocumentPathTableAdapter.GetData(caseNum, commnum).Count > 0 Then
Try
Me.SpGetLOMCDocumentPathTableAdapter.Fill(Me.DevGISDataSet.spGetLOMCDocumentPath, caseNum, commnum)
Dim docPath As New BindingSource
docPath = Me.SpGetLOMCDocumentPathBindingSource
Me.bnTIF.BindingSource = docPath
Dim b1 = New System.Windows.Forms.Binding("Text", docPath, "DocPath", True)
AddHandler b1.BindingComplete, AddressOf Me.HandleBindingCompleted
Me.lblDocPath.DataBindings.Add(b1)
Dim currentPath As String = Nothing
currentPath = Me.lblDocPath.Text
MessageBox.Show(b1.Control.Text)
If Not String.IsNullOrEmpty(currentPath) Then
If currentPath.Contains(".TIF") Then
LoadTIF()
End If
If currentPath.Contains(".pdf") Then
LoadPDF()
End If
End If
'FindImage()
Me.Show()
Catch ex As Exception
MessageBox.Show("Error: " & ex.Message.ToString)
End Try
Else
MessageBox.Show("Image not available. Please check FEMA and CAMSIS.")
Exit Sub
End If
End Sub
Private Sub HandleBindingCompleted(ByVal sender As Object, ByVal e As BindingCompleteEventArgs)
MessageBox.Show(String.Format("{0}: {1}", e.Binding.BindingMemberInfo.BindingMember, e.Binding.Control.Text))
If (Not e.Exception Is Nothing) Then
Debug.WriteLine(e.ErrorText)
End If
End Sub
使用if((buflen = read(fd1, &recs, sizeof(recs))) < 0){
而不是<= 0
,否则当返回值为0时,< 0
可能会在尝试取消引用具有未初始化值的sprintf(buffer ...
时出现错误
答案 3 :(得分:0)
你有一些问题: 1)bin_record的结构。它有char []并且可能溢出。 2)在sprintf中你不能设置缓冲区最大大小。最好像这样使用snprintf:
sprintf(buffer, 100, "%d, %s, %s, %f, %d\n", recs->id, recs->lname, recs->fname, recs->gpa, recs->iq);
3)用null填充缓冲区:
memset (buffer,'\0',100);