2015-12-19 89 views
0

我做節目有野牛在編輯一個PPM文件Ubuntu的給出,但我有一個分段故障核心轉儲的錯誤,我似乎無法修復它的用戶輸入,我的繼承人代碼:編輯文件時出現分段錯誤(核心轉儲)?

void ponto(int x, int y, char fname[100]){ 
    int r,g,b; 
    int i,j; 
    int col,row; 
    int c = 255; 

    FILE *myFile = fopen(fname, "r"); 
    if (myFile == NULL) 
    { 
    printf("Ficheiro nao existe"); 
    } 
    else 
    fscanf(myFile, "P3\n%d%d\n255\n ", &col, &row); 

    fscanf(myFile,"%d %d %d\n ",&r,&g,&b); 

    FILE *fout = fopen(fname,"w"); 

    fprintf(fout, "P3\n%d %d\n255\n",col,row); 

    for (j = 0;j < col;) 
    { 
    for (i = 0;i < row; i++) 
    { 
     if (j == y -1 && i == x - 1) 
     { 
     fprintf(fout,"0 0 0 "); 
     } 
     else 
     fprintf(fout,"%d %d %d ",r,g,b); 

    } 
    fprintf(fout,"\n"); 
    j++; 
    } 
    fclose(fout); 
} 

和繼承人我的yacc代碼:

%{ 
#include <stdio.h> 
#include "defs.h" 
#include "funcoes.h" 
Lista lista_variaveis = NULL; /* guarda o valor das variavaies definidas */ 
char * cfile = NULL; /* variavel currentfile para saber que ficheiro estamos a usar */ 
%} 

%union { 
     int valor; 
     RES resolucao; 
     COR color; 
     COOR cord; 
     char * fname; 
     char * idvar;} 

%type <resolucao> resol 
%type <valor> num 
%type <color> rgb 
%type <valor> expr 
%type <cord> coord 

%token <idvar> IDVAR 
%token <valor> INT 
%token <fname> FNAME 
%token SAIR NOVA ABRIR GUARDAR PONTO 

%start s 
%% 
s  : comando 
     ; 
comando : NOVA resol rgb ';'{makef($2.resx,$2.resy,$3.r,$3.g,$3.b); 
          cfile = "teste2.pnm";printf("%s",cfile); } comando      
     | ABRIR FNAME ';' {openf($2);cfile = $2}; comando 
     | PONTO coord ';' {ponto($2.xx,$2.yy,cfile);} comando  
     | GUARDAR    
     | defvar ';' comando 
     | SAIR   {return 0; /*termina */ } 
     ; 
coord : expr ',' expr { $$.xx = $1; $$.yy = $3;} 
     ; 
resol : expr 'x' expr { $$.resx = $1; $$.resy = $3;}  
     ; 
rgb : expr':'expr':'expr { $$.r = $1; $$.g = $3; $$.b = $5;} 
     ; 
num : num '+' num { $$ = $1 + $3;} 
     | num '*' num { $$ = $1 * $3;} 
     | INT   { $$ = $1;} 
     ; 
expr : num   { $$ = $1;} 
     | IDVAR  { $$ = valor_variavel(lista_variaveis, $1);} 
     ; 
defvar: IDVAR '=' num { define_variavel(&lista_variaveis,$1,$3);} 
     ; 

%%`` 
+2

請使用調試器來遍歷代碼,告訴我們錯誤發生的位置。 –

+2

我的猜測是該文件不存在程序正在查找的位置。你檢查NULL,但後面的'else'只適用於第一個'fscanf()'。第二個是無條件調用的,如果傳入一個NULL指針,你可以得到一個段錯誤。 – donjuedo

+2

另外,您正在使用輸入和輸出相同的文件名,並且同時打開。至少,這不是好習慣。因爲我從來沒有嘗試過,所以我不能說出行爲是什麼,但是如果'fopen()'調用寫入結果失敗,並且返回NULL指針,我不會感到驚訝。該指針根本不被檢查,並傳入'fprintf'()'。如果爲NULL,那可能是崩潰的另一個來源。 – donjuedo

回答

1

該代碼有幾個問題。

首先,在幾個評論中指出,下面的代碼將不可避免地出現段錯誤,如果要打開的文件不存在:

if (myFile == NULL) { 
    printf("Ficheiro nao existe"); 
} 
else 
    fscanf(myFile, "P3\n%d%d\n255\n ", &col, &row); 
fscanf(myFile,"%d %d %d\n ",&r,&g,&b); 

因爲if語句只阻止第一fscanf被稱爲如果myFileNULL。你應該插入錯誤消息後return(我也是固定的printf):

if (myFile == NULL) { 
    fputs("Ficheiro nao existe\n", stderr); 
    return; 
} 

fscanf(myFile, "P3\n%d%d\n255\n ", &col, &row); 
fscanf(myFile,"%d %d %d\n ",&r,&g,&b); 

其次,無疑是你的Flex文件有問題(在討論中的意見驗證)。如果您的flex文件具有以下動作:

{ yylval.fname = yytext; } 

那麼您違反了flex的合同。你是不允許出口的yytext指針的值,因爲它是指向內部彎曲,其內容可以是變幻莫測的緩衝區。事實上,flex甚至可能重新分配緩衝區,給你一個懸掛指針。

您必須字符串數據複製到自己的內存緩衝區 - 通常喜歡的東西strdup - 爲了將它傳遞給野牛。如果你不這樣做,yylval.fname指向的字符串的值可能在你嘗試使用它時發生了變化。這顯然會導致文件沒有找到(如果你幸運 - 它可能會導致其他文件被覆蓋)。

不要忘記free內存你strdup當你與它完成。

這一點也適用於IDVAR


第三,它是可能的pontoNULL作爲其第三(FNAME)參數來調用。在您的野牛文件,cfile被初始化爲NULL,再由NOVA陳述,或者從輸入的文件名由ABRIR語句修改爲"teste2.pnm"。但是,如果沒有這些語句是前PONTO聲明遇到cfile仍將NULL。您應該檢查該情況,或將cfile初始化爲有效的字符串;否則,ponto()中的fopen可能會出現段錯誤。


最後,你在你的comando製作中旬規則操作使用是有點古怪。我收集的意圖是堅持要麼GUARDARSAIR的最後一個聲明,但SAIR的行動中使用return 0很好地繞過了解析器的檢查,它是最後一條語句。所以你還不如寫了一個比較正常的左遞歸節目製作:

s : comando 
    | s comando 
comando 
    : NOVA resol rgb ';' 
    | ABRIR FNAME ';' 
    | PONTO coord ';' 
    | defvar ';' 
    | SAIR 
    | GUARDAR 

如果你真的想解析器來驗證最後一條語句必須是這兩個中的一個,你可以這樣做:

s : comandos ultimo 
comandos 
    : comando 
    | comandos comando 
ultimo 
    : SAIR 
    | GUARDAR 
commando 
    : NOVA resol rgb ';' 
    | ABRIR FNAME ';' 
    | PONTO coord ';' 
    | defvar ';'