Ir ao conteúdo
  • Cadastre-se

Duvida com Arquivos em C


Londer

Posts recomendados

Fala galera tudo bem, estou com um probleminha em C pra resolve.

estou tentando criar um programa que recebe o endereço de um arquivo ou o nome, nesses arquivos que exitem 2 no caso, um contem expressões logicas e o outro aritméticas, a parte que estou tendo problema na verdade é a que o programa tem que ler o que esta dentro de cada arquivo e exibir o resultado, Como exemplo no arquivo aritmético, na primeira linha 1+1, o programa deve ler e resolver a expressão e mostrar o resultado na tela e depois passar pra segunda linha do arquivo, fazendo isso até o final dele.

Obrigado, espero que possam me ajudar.

Link para o comentário
Compartilhar em outros sites

Esse foi o codigo que consegui até o momento.

 

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(){
 
char NomeArquivo[40];
 
printf("Digite o nome do arquivo: ");
scanf("%s", &NomeArquivo);
 
FILE *arq;
arq = fopen (NomeArquivo, "r");
 
if (arq == NULL)
printf("Erro no arquivo");
 
else{
 
printf("Ir de exprecoes ");
 
int i=0;
 
char linha[10];
char fixo[6];
 
while( (fgets(linha, sizeof(linha), arq)) != '\0'){
 
strncpy(fixo, linha, 5);
fixo[5] = '\0';
 
printf( "x = %s\n", fixo);
 
}
}
}
 
[/CODE]
Link para o comentário
Compartilhar em outros sites

#include <stdio.h>#include <stdlib.h>#include <string.h>void parserAritmetico(char *str) {    // ...} int main() {    int i=0;    char linha[10];    char fixo[6];     char NomeArquivo[40];    printf("Digite o nome do arquivo: ");    scanf("%s", &NomeArquivo);     FILE *arq;    arq = fopen (NomeArquivo, "r");     if (arq == NULL)        printf("Erro no arquivo");     else {        printf("Ir de exprecoes ");        while( fgets(linha, sizeof(linha), arq) != NULL) {            parserAritmetico(linha);        }    }    return 0;}
Pelo que eu entendi no código acima, a cada passagem do while a variável 'linha' vai ser valores assim:

"1+1"

"1 + 1"

"123 -40"

"10/2"

...

É isso?

Então o que você precisa é criar um PARSER. O parser vai pegar essa expressão que é apenas um conjunto de caracteres e vai tentar transformar ela pro padrão <numero> <sinal <numero>.

Um exemplo de como fazer isso:

- Assumindo que 'linha' é igual a: "123 + 45"

- Lendo a variável 'linha' da direita pra esquerda:

int x = 0;

int y = 0;

char sinal;

int mod = 1;

Na tabela ASCII os números de 0 a 9 estão nos valores de #48 até #57, então

- linha[7] é maior que 47 e menor que 58?

Caso seja verdadeiro, adiciona o valor em y.

- y += (linha[7] - 48) * mod; // y igual a 5

- mod = mod * 10;

- linha[6] é maior que 47 e menor que 58?

Caso verdadeiro:

- y += (linha[6] - 48) * mod; // y igual a 5 + 40, 45

- mod = mod * 10;

Quando chegar em linha[5] a expressão vai ser falsa.

Se linha[5] não é um número, significa que ela ou é um espaço em branco, ou um sinal.

Usando a mesma lógica anterior você checa isso e caso seja um sinal você armazena ele na variável 'sinal'.

Reseta o valor de 'mod' e repete o mesmo processo acima pra x.

No final você vai ter 'x' guardando o valor 123, 'y' com 45 e sinal igual a '+'.

Daí é só fazer 4 IFs pra testar os 4 sinais e imprimir o resultado:

if (sinal == '+') printf("%d + %d = %d\n", x, y, x+y);

if (sinal == '-') printf("%d - %d = %d\n", x, y, x-y);

...

Colocando isso em código:

int x = 0;int y = 0;int mod = 1;int *p = &y; // *p == ychar sinal;for (i = strlen(linha); i >= 0; --i) {    if (linha[i] > 47 && linha[i] < 58) {        // numero        *p += (linha[i] - 48) * mod;        mod *= 10;    } else {        if (linha[i] != ' ') {            // sinal            sinal = linha[i];            p = &x; // guardando agora os valores em x;            mod = 1;        }    }}switch (sinal) {case '+':    // ...printf(blablabla)    break;case '-':     // ...    break;case '/':     // ...    break;case '*':    // ...    break;}
Existe uma maneira mais fácil de fazer isso, caso as expressões aritméticas no arquivo sigam a mesmo padrão, que é usando a função strtok(). Essa função divide uma string em partes menores, separando ela por delimitadores. Se 'linha' for igual a "12+34" e você usar strtok(linha, "+"), a função vai separar 'linha' em duas strings "12" e "34". Daí é só converter elas pra números usando a lógica acima.

Exemplo da strtok:

http://www.cplusplus.com/reference/cstring/strtok/

Link para o comentário
Compartilhar em outros sites

#include <stdio.h>#include <stdlib.h>#include <string.h>void parserAritmetico(char *str) {    // ...} int main() {    int i=0;    char linha[10];    char fixo[6];     char NomeArquivo[40];    printf("Digite o nome do arquivo: ");    scanf("%s", &NomeArquivo);     FILE *arq;    arq = fopen (NomeArquivo, "r");     if (arq == NULL)        printf("Erro no arquivo");     else {        printf("Ir de exprecoes ");        while( fgets(linha, sizeof(linha), arq) != NULL) {            parserAritmetico(linha);        }    }    return 0;}
Pelo que eu entendi no código acima, a cada passagem do while a variável 'linha' vai ser valores assim:

"1+1"

"1 + 1"

"123 -40"

"10/2"

...

É isso?

Então o que você precisa é criar um PARSER. O parser vai pegar essa expressão que é apenas um conjunto de caracteres e vai tentar transformar ela pro padrão <numero> <sinal <numero>.

Um exemplo de como fazer isso:

- Assumindo que 'linha' é igual a: "123 + 45"

- Lendo a variável 'linha' da direita pra esquerda:

int x = 0;

int y = 0;

char sinal;

int mod = 1;

Na tabela ASCII os números de 0 a 9 estão nos valores de #48 até #57, então

- linha[7] é maior que 47 e menor que 58?

Caso seja verdadeiro, adiciona o valor em y.

- y += (linha[7] - 48) * mod; // y igual a 5

- mod = mod * 10;

- linha[6] é maior que 47 e menor que 58?

Caso verdadeiro:

- y += (linha[6] - 48) * mod; // y igual a 5 + 40, 45

- mod = mod * 10;

Quando chegar em linha[5] a expressão vai ser falsa.

Se linha[5] não é um número, significa que ela ou é um espaço em branco, ou um sinal.

Usando a mesma lógica anterior você checa isso e caso seja um sinal você armazena ele na variável 'sinal'.

Reseta o valor de 'mod' e repete o mesmo processo acima pra x.

No final você vai ter 'x' guardando o valor 123, 'y' com 45 e sinal igual a '+'.

Daí é só fazer 4 IFs pra testar os 4 sinais e imprimir o resultado:

if (sinal == '+') printf("%d + %d = %d\n", x, y, x+y);

if (sinal == '-') printf("%d - %d = %d\n", x, y, x-y);

...

Colocando isso em código:

int x = 0;int y = 0;int mod = 1;int *p = &y; // *p == ychar sinal;for (i = strlen(linha); i >= 0; --i) {    if (linha[i] > 47 && linha[i] < 58) {        // numero        *p += (linha[i] - 48) * mod;        mod *= 10;    } else {        if (linha[i] != ' ') {            // sinal            sinal = linha[i];            p = &x; // guardando agora os valores em x;            mod = 1;        }    }}switch (sinal) {case '+':    // ...printf(blablabla)    break;case '-':     // ...    break;case '/':     // ...    break;case '*':    // ...    break;}
Existe uma maneira mais fácil de fazer isso, caso as expressões aritméticas no arquivo sigam a mesmo padrão, que é usando a função strtok(). Essa função divide uma string em partes menores, separando ela por delimitadores. Se 'linha' for igual a "12+34" e você usar strtok(linha, "+"), a função vai separar 'linha' em duas strings "12" e "34". Daí é só converter elas pra números usando a lógica acima.

Exemplo da strtok:

http://www.cplusplus.com/reference/cstring/strtok/

 

 

 

 

Funcionou Obrigado, cheguei a esse codigo

 

else{ printf("Interpretador de exprecoes\n\n"); char linha[10];char fixo[6]; while((fgets(linha, sizeof(linha), arq)) != '\0'){ int resultado; int i;int x = 0;int y = 0;int mod = 1;int *p = &y; // *p == yint *l = &x;char sinal; for (i = strlen(linha); i >= 0; --i) {   if (linha[i] > 47 && linha[i] < 58) {       // numero       *l += (linha[i] - 48) * mod;       mod *= 10;   } else {       if (linha[i] != ' ') {           // sinal           sinal = linha[i];           *p = *l-y; // guardando agora os valores em x;           mod = 1;                      x = y - x;                  }   }} switch(sinal){case '+':   resultado = x + y;   break;case '-':    resultado = x - y;   break;case '/':    resultado = x / y;   break;case '*':   resultado = x * y;   break;} printf( "X = %d\n", x);printf( "Y = %d\n", y);printf( "SINAL = %c\n", sinal);printf( "%d %c %d = %d\n", x, sinal, y, resultado);printf("Resultado: %d\n\n",resultado); }} 

 

Funcionou Obrigado, cheguei a esse codigo

else{ printf("Interpretador de exprecoes\n\n"); char linha[10];char fixo[6]; while((fgets(linha, sizeof(linha), arq)) != '\0'){ int resultado; int i;int x = 0;int y = 0;int mod = 1;int *p = &y; // *p == yint *l = &x;char sinal; for (i = strlen(linha); i >= 0; --i) {   if (linha[i] > 47 && linha[i] < 58) {       // numero       *l += (linha[i] - 48) * mod;       mod *= 10;   } else {       if (linha[i] != ' ') {           // sinal           sinal = linha[i];           *p = *l-y; // guardando agora os valores em x;           mod = 1;                      x = y - x;                  }   }} switch(sinal){case '+':   resultado = x + y;   break;case '-':    resultado = x - y;   break;case '/':    resultado = x / y;   break;case '*':   resultado = x * y;   break;} printf( "X = %d\n", x);printf( "Y = %d\n", y);printf( "SINAL = %c\n", sinal);printf( "%d %c %d = %d\n", x, sinal, y, resultado);printf("Resultado: %d\n\n",resultado); }} 

 

mais agora outra duvida que tive, caso um sinal aparece mais de uma vez, como exemplo 35 + 25 - 8 ou 35 + (56-62) - 20 , precisarei armazenar esse sinal em outra variável certo? e os numero também?
 
obrigado pela ajuda.
Link para o comentário
Compartilhar em outros sites

Um parser normalmente tem duas etapas. O analisador léxico, onde você pega o input (que nessa caso são strings armazenadas no arquivo) e transforma ele em tokens (as partes dele, como <numero> <sinal> <espaço> etc), e o analisador sintático onde você pega os tokens, usa alguma lógica nele (nesse caso a lógica é aritmética) e retorna o resultado.

Como o exemplo que eu dei era bem simples, só tinha dois tipos de tokens (numero e sinal) então eu não precisei organizar os tokens nem fazer nada com eles:

for (i = strlen(linha); i >= 0; --i) {    if (linha[i] > 47 && linha[i] < 58) {        // numero        *p += (linha[i] - 48) * mod;        mod *= 10;    } else {        if (linha[i] != ' ') {            // sinal            sinal = linha[i];            p = &x; // guardando agora os valores em x;            mod = 1;        }    }}
'p' é um ponteiro que aponta pra y e armazena os números iniciais nele. Assim que aparece um sinal no código (qualquer coisa que não seja número nem espaço em branco), eu guardo o sinal numa variável e faço 'p' apontar agora pra x, armazenando os próximos números nele.

Depois disso vou direto pro switch. Como são as mesmas variáveis sempre, não precisa usar muita lógica de programação.

Se a expressão fosse mais complexa, com vários números, sinais e parenteses, aí sim você precisa criar um mini analisador léxico. Alguma função que pega os números, sinais, simbolos e adiciona eles numa lista (uma pilha é melhor), depois pega essa lista e vai resolvendo as expressões.

Por exemplo, se tiver uma string assim: "1 * 2 - 3 + 5"

O analisador léxico vai transformar isso em duas listas:

numeros[4] = { 1, 2, 3, 5 };

sinais[3] = { '*', '-', '+' };

E o analisador sintático vai usar a seguinte lógica:

- sinais[0] é '*', e pra fazer uma multiplicação eu preciso de dois números, então eu retiro os dois primeiros elementos da lista numeros[], multiplico eles e devolvo o resultado:

numeros[4] = { 2, 3, 5 };

sinais[3] = { '-', '+' };

- sinais[1] é '-', pra uma subtração retiro dois números da lista numeros[] subtraio e devolvo :

numeros[4] = { -1, 5 };

sinais[3] = { '+' };

- ...repete o mesmo com sinais[2].

...

É mais ou menos isso. Existem maneiras mais simples de fazer isso, principalmente se você não considerar certas coisas como a precedencia de operadores (multiplicação e divisão sempre vem antes de soma e subtração) mas a lógica é essa.

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!