paulo1205
(usa Ubuntu)
Enviado em 10/12/2018 - 14:56h
phellipe_ escreveu:
olá...
estou com esse codigo, mas não consigo fazer funcionar!
Você cometeu diversos erros comuns em iniciantes.
Uma coisa que eu sempre recomendo, porque ajuda a diagnosticar a grande maioria de erros desse tipo, é ligar o máximo possível de opções de diagnóstico e alerta do compilador. No caso do GCC, quer usado diretamente, quer quando invocado pelo ambiente gráfico de desenvolvimento, eu recomendo as seguintes opções de diagnóstico:
-std=c11 -Wall -Werror -pedantic-errors -O2
Legenda:
-std=c11 pede que se utilize a versão de 2011 do padrão (
standard, de onde vem “
-std”) do C;
-Wall faz com que o compilador mostre todas (“
all”) as mensagens de alerta (
warning, de onde vem “
-W”);
-Werror transforma todas as mensagens de alerta em erros, impedindo a compilação de prosseguir (para que você seja forçado a corrigir o problema apontado, em vez de preguiçosamente deixar o aviso passar e “torcer para funcionar assim mesmo”);
-pedantic-errors faz com que o compilador seja pedantemente intransigente com relação a código perigoso, e trata todas as violações como erros que impedem a compilação de prosseguir; e
-O2 liga o segundo nível de otimização de código, que, embora não tenha propósito original de servir para diagnóstico, ajuda a identificar alguns casos de código inacessível e variáveis que ficam sem uso.
Ao compilar seu programa original (que eu chamei de
calc.c) apenas com o comando “gcc calc.c”, ele gerou 13 alertas, mas produziu um código executável. Usando as opções de diagnóstico que eu sugeri acima, foram 19 mensagens de erro (não mais apenas alerta), com descrições precisas de causa, incluindo erros ao usar
scanf():
calc.c:4:31: error: ISO C does not allow extra ‘;’ outside of a function [-Wpedantic]
int strop, str0, str1, a, b;;
^
calc.c: In function ‘mais’:
calc.c:9:12: error: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration]
str0 = strlen(n0);
^~~~~~
calc.c:9:12: error: incompatible implicit declaration of built-in function ‘strlen’ [-Werror]
calc.c:9:12: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
calc.c: In function ‘menos’:
calc.c:22:12: error: incompatible implicit declaration of built-in function ‘strlen’ [-Werror]
str0 = strlen(n0);
^~~~~~
calc.c:22:12: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
calc.c: In function ‘vezes’:
calc.c:35:12: error: incompatible implicit declaration of built-in function ‘strlen’ [-Werror]
str0 = strlen(n0);
^~~~~~
calc.c:35:12: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
calc.c: In function ‘divide’:
calc.c:48:12: error: incompatible implicit declaration of built-in function ‘strlen’ [-Werror]
str0 = strlen(n0);
^~~~~~
calc.c:48:12: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
calc.c: In function ‘main’:
calc.c:68:15: error: format ‘%[^
’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[10]’ [-Werror=format=]
scanf("%[^\n]s%*c", &op);
~~~^~ ~~~
calc.c:69:13: error: incompatible implicit declaration of built-in function ‘strlen’ [-Werror]
strop = strlen(op);
^~~~~~
calc.c:69:13: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
calc.c:71:13: error: comparison between pointer and integer
if(op > 47 && op < 58){
^
calc.c:71:24: error: comparison between pointer and integer
if(op > 47 && op < 58){
^
calc.c:72:14: error: comparison between pointer and integer
if(op == 1){
^~
calc.c:75:19: error: comparison between pointer and integer
else if(op == 2){
^~
calc.c:78:19: error: comparison between pointer and integer
else if(op == 3){
^~
calc.c:81:19: error: comparison between pointer and integer
else if(op == 4){
^~
calc.c: In function ‘mais’:
calc.c:20:3: error: control reaches end of non-void function [-Werror=return-type]
}
^
calc.c: In function ‘menos’:
calc.c:33:3: error: control reaches end of non-void function [-Werror=return-type]
}
^
calc.c: In function ‘vezes’:
calc.c:46:3: error: control reaches end of non-void function [-Werror=return-type]
}
^
calc.c: In function ‘divide’:
calc.c:59:3: error: control reaches end of non-void function [-Werror=return-type]
}
^
calc.c: In function ‘main’:
calc.c:68:5: error: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Werror=unused-result]
scanf("%[^\n]s%*c", &op);
^~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
qualquer digito que faço eu saio do programa:
#include <stdio.h>
#include <stdlib.h>
Você não incluiu <string.h>, para poder trabalhar com funções que manipulam
strings.
Variáveis globais são um dos tipos de coisas que se deve usar com moderação. Contudo, você fez globais todos os dados do programa, incluindo varáveis usadas como contadores em laços de repetição.
Não chega a ser errado, mas não definitivamente é usual. Seria melhor evitar.
int strop, str0, str1, a, b;;
char op[10], n0[1000], n1[1000];
float t;
float mais(){
str0 = strlen(n0);
str1 = strlen(n1);
A função
strlen() mede o comprimento de uma
string. É isso mesmo que você quer?
for(a = 0; a <= str0; a++){
for(b = 0; b <= str1; b++){
t = a + b;
printf("Result: %.2f\n", t);
break;
Por que esse
break? Na prática, ele mata o laço de repetição interno logo após a primeira iteração, pois transforma o
for mais interno em algo equivalente ao seguinte
if.
if((b=0)<=str1){ // Essa condição será sempre verdadeira, porque str1 será sempre maior ou igual a zero
t=a+b; // Ou “t=a;”, dado que b será sempre zero.
printf("Result: %.2f\n", t);
}
Não entendi o propósito desses laços de repetição. Você pega os comprimentos de cada
string e depois cria dois laços de repetição que percorrem o caminho de zero até cada um dos comprimentos, somando os valores intermediários das variáveis de controle de cada laço de repetição (não dos dados que elas indexariam), e ainda por cima com a particularidade de que o laço de repetição mais interno é prematuramente interrompido.
Você disse que a função retorna um valor do tipo
float, mas cadê o comando de retorno desse valor?
Esse problema e os já apresentados acima se repetem nas outras funções. Por isso, não vou apontá-los especificamente de novo.
float menos(){
str0 = strlen(n0);
str1 = strlen(n1);
for(a = 0; a <= str0; a++){
for(b = 0; b <= str1; b++){
t = a - b;
printf("Result: %.2f\n", t);
break;
}
}
}
float vezes(){
str0 = strlen(n0);
str1 = strlen(n1);
for(a = 0; a <= str0; a++){
for(b = 0; b <= str1; b++){
t = a * b;
printf("Result: %.2f\n", t);
break;
}
}
}
float divide(){
str0 = strlen(n0);
str1 = strlen(n1);
for(a = 0; a <= str0; a++){
for(b = 0; b <= str1; b++){
t = a / b;
printf("Result: %.2f\n", t);
break;
}
}
}
int main(){
printf("||=======================================================||\n");
printf("||=== xcal v3.0 by: phellipe_ ===||\n");
printf("||=======================================================||\n");
printf("|| Escolha uma opção ||\n");
printf("|| (1) + (2) - (3) x (4) ÷ (0) Sair ||\n");
printf("||=======================================================||\n");
printf("Operação: ");
scanf("%[^\n]s%*c", &op);
Você tentou usar
scanf() de uma maneira engenhosa. Contudo,
scanf() é uma função bastante complexa (eu reputo como a função mais complexa de toda a biblioteca de funções padronizadas do C), e você acabou se atrapalhando de diversas maneiras. Eis alguns dos equívocos:
•
"%[" é uma conversão de seu próprio direito, e utiliza um argumento pós-fixado terminado com o caráter “
]” (no seu caso, tal argumento pós-fixado é “
^\n”).
Não se trata de um modificador da conversão "%s", de modo que aquele caráter
s que vem depois do fechamento de colchetes não tem o sentido que provavelmente você imaginou. (Esse é um erro muito comum em apostilas e por parte de professores que não sabem C tão bem assim. Portanto, muito cuidado com o material que você recebe!)
• O caráter
's' presente na
string de formatação é interpretado como algo a ser buscado literalmente na
string digitada pelo usuário do programa. Se esse
's' não for encontrado na
string, a função
scanf() vai interromper o processamento antes de chegar ao final da
string de formatação.
• Entretanto, o
's' nunca será encontrado, porque a conversão que vem imediatamente antes dele não será interrompida até que apareça um
'\n' (ou que ocorra um erro de leitura). Ao aparecer um
'\n' na entrada, a conversão
"%[" termina, deixando o
'\n' no
buffer de entrada para ser comparado com o que vem a seguir. Mas como o que vem a seguir na
string de formatação é um
's', esse
'\n' não vai lhe corresponder, sendo deixado ainda no
buffer de entrada e provocando a interrupção prematura do processamento de
scanf().
• Por conta da interrupção prematura, também o
"%*c" nunca será atingido e, portanto, não provocará o consumo de nenhum caráter do
buffer de entrada.
• Existe um erro de correspondência de tipos entre a conversão
"%[" e o argumento
&op: a primeira espera um ponteiro para caracteres, e o tipo da segunda é “ponteiro para
arrays com 10 elementos do tipo caráter”. Você deveria ter usado como argumento apenas “
op” (sem o operador
&), de modo que o o
array de caracteres seja automaticamente convertido em ponteiro para caracteres.
• Há um risco de segurança, pois você está solicitando a leitura de uma quantidade ilimitada de caracteres para um destino que tem comprimento de apenas 10
bytes. Seria melhor que você limitasse a quantidade máxima de caracteres que podem ser recebidos.
• Ainda pelo ponto de vista de segurança do código, você não testa sequer se a leitura foi bem sucedida antes de prosseguir executando código que depende do que deve ter sido lido. O resultado disso é totalmente indefinido.
Assim sendo, seria bom que você mudasse a forma de fazer sua leitura.
A primeira coisa a fazer seria uma leitura cuidadosa do comportamento da função
scanf() (que, como eu disse, é bastante complexa), até para entender os pontos em que errou e como você os deve corrigir. Contudo, se você é iniciante, é possível que a documentação toque em pontos que você ainda não domina. Se for o caso, pesquise, ou volte aqui expondo sua dúvida.
Depois disso, não apenas você deve corrigir a
string de formatação, mas também testar o valor de retorno de
scanf(), para ver se ela realmente leu alguma coisa. (Eu adicionalmente mudaria também os tipos dos seus dados. Não consegui entender por que motivo você está usando
strings com sua calculadora, em lugar de dados numéricos.)
strop = strlen(op);
if(strop == 1){
if(op > 47 && op < 58){
Seria melhor usar algo como “
if(isdigit(op))”.
if(op == 1){
mais();
}
else if(op == 2){
menos();
}
else if(op == 3){
vezes();
}
else if(op == 4){
divide();
}
else if(op == 0){
printf("Saindo... OK!");
exit(0);
}
else{
printf("Digite uma opção válida!\n");
}
}
}
return 0;
}