2015-12-19 2 views
0

Делаю программу с зубрами в убунту, которая редактирует файл частей на миллион, учитывая введенный пользователь, но у меня основная ошибки сегментации сбрасывала ошибку, и я не могу показаться, чтобы исправить это, Heres моего кода:Ошибка сегментации (сбрасывание ядра) при редактировании файла?

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); 
} 

и Heres мой код 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 передан, вы можете получить segfault. – 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 от вызова, если myFile - NULL. Вы должны вставить 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.


В-третьих, возможно ponto называться с NULL в качестве третьего (Fname) аргумент. В вашем бизоне файл cfile инициализирован до NULL, а затем изменен на "teste2.pnm" оператором NOVA или именем файла из ввода оператором ABRIR. Но если ни один из этих операторов не встречается перед оператором PONTO, cfile по-прежнему будет NULL. Вы должны либо проверить этот случай, либо инициализировать cfile действительной строке; в противном случае fopen в ponto(), вероятно, будет segfault.


Наконец, ваше использование в середине правила действий в ваших comando производств немного эксцентричным.Я собираюсь намереваться настаивать на том, что последнее заявление либо GUARDAR, либо SAIR, но использование return 0 в действии для SAIR довольно хорошо обходит проверку синтаксического анализатора, что это последнее утверждение. Таким образом, вы, возможно, также написали более нормальную левую рекурсию производственной программы:

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 ';' 
Смежные вопросы