Help na funções void

1. Help na funções void

William Freitas
heoresh

(usa Outra)

Enviado em 17/03/2017 - 20:40h

#include <stdio.h>
#include <stdlib.h>

void verbin();

int main() {
verbin();
return 0;
}
void verbin()
{ printf("\nOLA!");
system("pause");
}



Ja tentei de tudo mas sempre da um erro de "undefined reference to `verbin'"
Não sei o que fazer me ajudem


  


2. Re: Help na funções void

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 17/03/2017 - 21:48h

Ao meu ver, o código compila. Veja: https://ideone.com/J5qOCS

Que compilador e versão você está usando?
Qual a linha de comando que está utilizando para compilar?


3. Re: Help na funções void

Perfil removido
removido

(usa Nenhuma)

Enviado em 17/03/2017 - 21:56h

tenta criar outro source. poder ser erro no arquivo fonte, abre o source com o bloco de notas, e ver se o códico esta correto. as vezes o códico não é atualizado no arquivo fonte.


4. Re: Help na funções void

William Freitas
heoresh

(usa Outra)

Enviado em 17/03/2017 - 22:00h

uilianries escreveu:

Ao meu ver, o código compila. Veja: https://ideone.com/J5qOCS

Que compilador e versão você está usando?
Qual a linha de comando que está utilizando para compilar?


onde eu faço para ver a versão do compilador?
estou usando o code::blocks



5. Re: Help na funções void

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/03/2017 - 12:04h

Eu também não consegui reproduzir o erro que você indicou, pois o seu programa parece correto, tanto em C quanto em C++.

Para receber esse erro, talvez o problema esteja em alguma coisa que você não nos disse.

A primeira dessas coisas é se você estiver tentando compilar seu programa como C ou como C++. Ele parece escrito em C puro, mas talvez você esteja tentando compilá-lo como C++, e isso daria margem para outras possíveis causas para o erro recebido. Especificamente, refiro-me ao name mangling usado para habilitar sobrecarga de funções.

Alguma chance de você ter mexido nos arquivos de cabeçalho, tentando colocar a declaração da função ali?

Por fim, será que você não cometeu um erro de digitação no programa original, erro esse que você instintivamente corrigiu na hora de transcrever o programa aqui no fórum? Pode ser um erro bobo, tal como colocar uma letra maiúscula na hora de implementar a função (e.g. “Verbin” ou “verbIn”, que, dependendo da fonte usada no editor de textos, pode ser difícil de identificar), ou inverteu a ordem das letras?


Sei que algumas das minhas perguntas parecem absurdas. Mas o são porque mais absurdo ainda é você receber erro num programa que está visualmente correto.


6. Re: Help na funções void

William Freitas
heoresh

(usa Outra)

Enviado em 18/03/2017 - 13:23h

paulo1205 escreveu:

Eu também não consegui reproduzir o erro que você indicou, pois o seu programa parece correto, tanto em C quanto em C++.

Para receber esse erro, talvez o problema esteja em alguma coisa que você não nos disse.

A primeira dessas coisa é se você tentando compilar seu programa como C ou como C++. Ele parece escrito em C puro, mas talvez você esteja tentando compilá-lo como C++, e isso daria margem para outras possíveis causas para o erro recebido. Especificamente, refiro-me ao name mangling usado para habilitar sobrecarga de funções.

Alguma chance de você ter mexido nos arquivos de cabeçalho, tentando colocar a declaração da função ali?

Por fim, será que você não cometeu um erro de digitação no programa original, erro esse que você instintivamente corrigiu na hora de transcrever o programa aqui no fórum? Pode ser um erro bobo, tal como colocar uma letra maiúscula na hora de implementar a função (e.g. “Verbin” ou “verbIn”, que, dependendo da fonte usada no editor de textos, pode ser difícil de identificar), ou inverteu a ordem das letras?


Sei que algumas das minhas perguntas parecem absurdas. Mas o são porque mais absurdo ainda é você receber erro num programa que está visualmente correto.

É em C!
Quando eu copiei o codigo para cá acabei copiando errado e por isso, fiz as modificações



7. Re: Help na funções void

William Freitas
heoresh

(usa Outra)

Enviado em 18/03/2017 - 13:56h

Aqui esta o meu verdadeiro projeto!
Eu ja havia trabalho com void, mas não sei o que realmente esta me atrapalhando '-'


http://pastebin.com/S137tfPX


8. Re: Help na funções void

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/03/2017 - 15:06h

O problema não é o void.

O programa que você postou on-line tem vários erros, mas o compilador indica, por meio de mensagens de erro, quais são eles e os motivo de serem errados, de modo que você pode corrigi-los.

Abaixo eu mostro as mensagens de erro e dou algumas dicas sobre como corrigir algumas delas. Note que eu compilei com o GCC, usando opções que aumentam o nível de diagnóstico do código.

$ gcc -Wall -Werror -O2 -pedantic-errors x.c
x.c: In function ‘main’:
x.c:17:12: error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[100]’ [-Werror=format=]
printf("%s", &nome);
^


Remova o “&”.

x.c:166:12: error: implicit declaration of function ‘getch’ [-Wimplicit-function-declaration]
op = getch();
^
x.c:176:16: error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[100]’ [-Werror=format=]
printf("%s", &nome);
^


Idem.

x.c:10:16: error: unused variable ‘x’ [-Werror=unused-variable]
int aux=0, x,tams, cont1=0, bina[100][8];
^
x.c: In function ‘verbin’:
x.c:345:10: error: type of ‘tams’ defaults to ‘int’ [-Wimplicit-int]
void verbin(tams,bina,nome)
^


Esse método de definir função é obsoleto. Com ele, todos os parâmetros são considerados inteiros, e isso contradiz a declaração que você fez anteriormente.

Você deve colocar os tipos dos argumentos também na definição da função, e eles têm de corresponder ao que você tiver colocado na declaração.

O tipo errado explica outras mensagens abaixo, como as que dizem que bina não é um array. Não é mesmo, pois a sintaxe obsoleta faz o compilador entender que ela seria uma variável do tipo int.

x.c:345:10: error: type of ‘bina’ defaults to ‘int’ [-Wimplicit-int]
x.c:345:10: error: type of ‘nome’ defaults to ‘int’ [-Wimplicit-int]
x.c:345:10: error: argument ‘bina’ doesn’t match prototype
x.c:6:6: error: prototype declaration
void verbin(int tams, int bina[100][8], char nome[100]);
^
x.c:345:10: error: argument ‘nome’ doesn’t match prototype
void verbin(tams,bina,nome)
^
x.c:6:6: error: prototype declaration
void verbin(int tams, int bina[100][8], char nome[100]);
^
x.c:348:51: error: subscripted value is neither array nor pointer nor vector
{printf("\n%c: %d%d%d%d%d%d%d%d", nome[x], bina[x][0], bina[x][1],
^
x.c:348:60: error: subscripted value is neither array nor pointer nor vector
{printf("\n%c: %d%d%d%d%d%d%d%d", nome[x], bina[x][0], bina[x][1],
^
x.c:348:72: error: subscripted value is neither array nor pointer nor vector
{printf("\n%c: %d%d%d%d%d%d%d%d", nome[x], bina[x][0], bina[x][1], bin
^
x.c:348:84: error: subscripted value is neither array nor pointer nor vector
intf("\n%c: %d%d%d%d%d%d%d%d", nome[x], bina[x][0], bina[x][1], bina[x][2], bin
^
x.c:348:96: error: subscripted value is neither array nor pointer nor vector
%d%d%d%d%d%d%d%d", nome[x], bina[x][0], bina[x][1], bina[x][2], bina[x][3], bin
^
x.c:348:108: error: subscripted value is neither array nor pointer nor vector
%d%d", nome[x], bina[x][0], bina[x][1], bina[x][2], bina[x][3], bina[x][4], bin
^
x.c:348:120: error: subscripted value is neither array nor pointer nor vector
x], bina[x][0], bina[x][1], bina[x][2], bina[x][3], bina[x][4], bina[x][5], bin
^
x.c:348:132: error: subscripted value is neither array nor pointer nor vector
0], bina[x][1], bina[x][2], bina[x][3], bina[x][4], bina[x][5], bina[x][6], bin
^
x.c:348:144: error: subscripted value is neither array nor pointer nor vector
][1], bina[x][2], bina[x][3], bina[x][4], bina[x][5], bina[x][6], bina[x][7]);
^
x.c: In function ‘main’:
x.c:14:5: error: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Werror=unused-result]
scanf(" %[^\n]s", nome);
^


Essa mensagem e as mensagens semelhantes que ocorrem abaixo quando você usa system)() são para a melhoria da qualidade do programa.

O GCC permite que se coloquem atributos nas declarações de funções. O Ubuntu, que é o sistema que eu uso, emprega tais atributos para marcar funções que sinalizam execução incorreta através do valor de retorno, principalmente quando uma execução com erro pode comprometer a segurança ou a integridade da execução do restante do programa.

Ao colocar atributos que sinalizam a omissão da verificação da execução com erro de funções que leem da entrada padrão (como scanf()) ou que interagem diretamente com o recursos externos ao programa (como system()), a ideia é induzir você a usar um estilo de programação mais seguro.

No caso específico acima, um erro que poderia acontecer seria o fim dos dados de entrada antes de começar a ler os caracteres do nome. Nesse caso, o conteúdo de nome ficaria indefinido, o que poderia ser um risco para o restante do programa.

Além do aspecto de segurança, sua string de formatação tem um erro. Mas eu falarei sobre o uso de scanf() numa resposta à parte.

x.c:16:5: error: ignoring return value of ‘system’, declared with attribute warn_unused_result [-Werror=unused-result]
system("cls");
^
x.c:160:7: error: ignoring return value of ‘system’, declared with attribute warn_unused_result [-Werror=unused-result]
system("cls");
^
x.c:169:9: error: ignoring return value of ‘system’, declared with attribute warn_unused_result [-Werror=unused-result]
system("cls");
^
x.c:173:9: error: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Werror=unused-result]
scanf(" %[^\n]s", nome);
^
x.c:175:9: error: ignoring return value of ‘system’, declared with attribute warn_unused_result [-Werror=unused-result]
system("cls");
^
x.c:320:9: error: ignoring return value of ‘system’, declared with attribute warn_unused_result [-Werror=unused-result]
system("cls");
^
x.c:326:9: error: ignoring return value of ‘system’, declared with attribute warn_unused_result [-Werror=unused-result]
system("cls");
^
cc1: all warnings being treated as errors



9. Re: Help na funções void

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/03/2017 - 03:04h

Como eu mencionei na mensagem anterior, sua string de formatação de scanf() tinha um erro. Eis o que você fez.

scanf(" %[^\n]s", nome); 


Vamos olhar cada pedaço da string:

1) O espaço no começo da string server para suprimir qualquer quantidade (inclusive zero) espaços em branco (incluindo marcas de fim de linha remanescentes de leituras anteriores) antes de começar a ler os nomes.

2) A especificação de conversão “%[^\n]” significa que você vai ler uma quantidade qualquer (inclusive zero, e sem limite máximo) de caracteres diferentes da marca de fim de linha, e vai guardá-los em sucessivas posições de memória a partir do endereço indicado por nome.

3) O caráter “s” é procurado isoladamente na entrada, após o fim da leitura da string.

Como a leitura de string só termina em quando chega um caráter de fim de linha, quando se chega ao fim do arquivo ou quando ocorre um erro, o terceiro pedaço da string de formatação vai sempre falhar.

Perceba que a conversão "%[" é diferente da conversão "%s". O que vem entre colchetes não é um modificador de uma conversão "%s", colocado entre o sinal de porcentagem e a letra “s”. "%[" é uma conversão de pleno direito, que recebe argumentos pospostos sobre quais caracteres devem ser incluídos (ou excluídos) da conversão, e esses argumentos são encerrados pela presença do caráter “]” após a especificação de um ou mais elementos do conjunto de caracteres a ser considerado para a extração da string. Por ser uma conversão completa, ela aceita os mesmos modificadores que as outras conversões (e.g. largura máxima, reordenamento de argumentos, supressão de atribuição etc.), dispostos entre o sinal de porcentagem e o caráter que indica a conversão.

-----------

O código abaixo, fartamente comentado, exemplifica como fazer a leitura do nome usando uma conversão correta e segura, e como tratar os possíveis casos de erro sinalizados por scanf(). Se parecer complicado, é porque é complicado mesmo! Eu costumo dizer que scanf() é uma das funções mais complicadas da biblioteca padrão do C.

	int r, a, b, c;

nome[99]='\0'; // Proteção, pois nem sempre scanf() coloca o terminador na string.
a=b=c=0;
// contador de quantos caracteres de espaçamento foram consumidos
// após a supressão de caracteres em branco
// ||
// || contador do total de caracteres consumidos por scanf()
// || ao final da leitura do nome
// || ||
// || || contador do total de caracteres consumidos
// || || ao final da string de formatação
// || || ||
// VV VV VV
r=scanf(" %n%99[^\n]%n%*1[\n]%n", &a, nome, &b, &c);
// ^ ^^^^^^^^ ^^^^^^^
// | |||||||| |||||||
// | |||||||| converte string composta apenas por caracteres '\n',
// | |||||||| com tamanho máximo de um caráter, mas o asterisco
// | |||||||| indica que não haverá atribuição da string lida a
// | |||||||| nenhum argumento
// | ||||||||
// | converte uma string composta por caracteres diferentes de '\n',
// | com tamanho máximo de 99 bytes, atribuindo-a ao array ‘nome’.
// |
// provoca a supressão de qualquer quantidade de caracteres em branco
// no começo do buffer de entrada
if(r==EOF){
/*
Erro de leitura, possivelmente devido a fim prematuro de dados na
entrada, ou nenhuma parte da string de formatação corresponde à entrada.

Você pode querer testar o resultado de ferror(stdin) e feof(stdin) para
decidir como proceder.
*/
if(ferror(stdin)){
/* Trata erro de leitura. */
}
else{
/* Trata fim de arquivo. */
}
}
else if(r==1){
/*
Compara com o número de conversões com atribuição solicitado. Se
for igual, todas as conversões com atribuição foram bem-sucedidas.

Note que as ocorrências de “%n” fazem atribuições, mas não con-
versões de dados da entrada. Logo não entram na conta. Tampouco
entra a conversão cuja atribuição foi suprimida pela presença do
asterisco.
*/
// Alguns dos testes abaixo ajudam a examinar a consistência dos dados.
if(a==b){
/*
Equivalente a testar se strlen(nome)==0, porém mais rápido.

No seu caso particular, essa condição provavelmente nunca vai
ocorrer, já que '\n' é considerado um espaço em branco, e seria
suprimido da entrada antes de começar a ler o nome, por causa
do espaço em branco no início da string de formatação.

Contudo, se a supressão de espaços em branco não estivesse
presente, ou se fosse outro o conjunto de caracteres a ser
suprimido, a condição aqui testada poderia ser útil para
impedir o uso de um nome vazio.
*/
}
else if(c>b){
/*
Nome tem 99 ou menos carcteres e havia um sinal de fim
de linha na entrada, que foi consumido. Certamente o nome lido é
válido, e você pode usá-lo aqui.
*/
}
else if(ferror(stdin)){
/*
Truncamento do nome por erro de leitura. Talvez seja perigoso
usar o nome truncado nessa situação.
*/
}
else if(feof(stdin)){
/*
Truncamento do nome devido ao fim dos dados na entrada.
Possivelmente menos crítico do que o truncamento por erro,
mas depende da aplicação decidir se convém ou não usar o nome
lido nesse caso.
*/
}
else{
/*
Usuário tentou digitar um nome longo demais, e os caracteres
excedentes não foram consumidos por scanf(), permanecendo no
buffer de entrada.

Além de tratar o truncamento do nome, se você não quiser que
os caracteres excedentes afetem futuras operações de leitura,
terá de tirá-los do buffer.
*/
}
}
else{
/*
Valor retornado por scanf() é diferente da quantidade total solicitada
de conversões com atribuição de valor, de modo que ocorreu algum
problema de formatação ou de erro durante a execução da função.

No seu caso particular, só foi solicitada uma conversão com atribuição,
logo o valor de r neste ponto do programa seria zero. Contudo, se você
tivesse pedido N conversões na mesma string de formatação, qualquer
valor entre 0 e N-1 seria indicativo de falha parcial, e uma aplicação
bem comportada deveria saber tratar qualquer um desses casos.

Mais ainda: sua string de formatação é composta apenas de elementos
se podem indicar sucesso em caso de “zero ou mais” ocorrências (tanto
a supressão de espaços quanto as conversões de strings). Então você
provavelmente nunca terá um caso de sucesso parcial, e a única possi-
bilidade de não sucesso total provavelmente será mesmo o caso em que
r==EOF.
*/
}


Mudar o modo de ler pode ajudar a evitar uma parte da complicação. Eis como conseguir funcionalidade semelhante com fgets(), ao custo de ter uma posição a menos disponível para guardar o nome no array nome, uma vez que fgets() transfere a marca de fim de linha para o array lido, a fim de facilitar justamente o diagnóstico de erros.

	if(
// Pula espaços em branco
scanf(" ")==EOF ||
// Lê linha após espaços em branco
fgets(nome, sizeof nome, stdin)==NULL
){
/*
Erro de leitura ou fim de arquivo antes de receber qualquer dado.
Não há nome válido com que se trabalhar.
*/
if(ferror(stdin)){
/* Trata erro de leitura. */
}
else{
/* Trata fim de arquivo. */
}
}
else{
size_t len=strlen(nome);
if(nome[len]!='\n'){
/*
Falta a marca de fim linha.
*/
if(len<sizeof nome-1){
/*
Ocorreu truncamento antes de se consumirem todas as
posições de ‘nome’.
*/
if(ferror(stdin)){
/*
Trata erro de leitura. Pode ser perigoso considerar o
nome lido como válido.
*/
}
else{
/*
Trata fim de arquivo. Tratar o nome como válido pode ser
aceitável ou não, dependendo da aplicação.
*/
}
}
else{
/*
Todas as posições foram ocupadas, mas sem a marca de fim de
linha: o usuário digitou um nome grande demais.

Você possivelmente vai querer descartar os dados lidos e
limpar os caracteres que ainda estiverem no buffer de
entrada, e depois tentar ler o nome novamente.
*/
}
goto saida; // Sim, é goto mesmo!
}
else{
/*
Marca de fim de linha presente. Suprime-a, pois você provavel-
mente não vai querê-la como parte do nome.
*/
nome[len--]='\0';
}
/*
Aqui vai um nome válido e não-nulo, com no máximo
‘sizeof nome-2’ caracteres, que você pode usar à vontade.
*/
}
saida:


Se você não quiser perder um byte do array, terá de usar uma variação que cria um segundo array com espaço para um caráter a mais, e depois copia dado lido (sem o '\n') de volta para o array original.

	char nome_mais_lf[1+sizeof nome];  // buffer com um byte a mais para conter quebra de linha
if(
// Pula espaços em branco
scanf(" ")==EOF ||
// Lê linha após espaços em branco
fgets(nome_mais_lf, sizeof nome_mais_lf, stdin)==NULL
){
/*
Erro de leitura ou fim de arquivo antes de receber qualquer dado.
Não há nome válido com que se trabalhar.
*/
if(ferror(stdin)){
/* Trata erro de leitura. */
}
else{
/* Trata fim de arquivo. */
}
}
else{
char *const ultimo=nome+sizeof nome-1;
char *p, *q;

/*
Copia nome lido de ‘nome_mais_lf’ para ‘nome’, suprimindo eventual
quebra de linha.
*/
*ultimo='\0'; // Garante de antemão o terminador em ‘nome’.
for(p=nome, q=nome_mais_lf; p<ultimo && (*p=*q)!='\0'; p++, q++)
if(*p=='\n'){
*p='\0';
break;
}
/*
Neste ponto, p==nome+strlen(nome) e com certeza *p=='\0'.

Por sua vez, q==nome_mais_lf+strlen(nome), mas não necessariamente
*p==*q.
*/

if(*q=='\n'){
/*
A marca de fim de linha foi encontrada por fgets(), e todos os
caracteres antes dela foram copiados com sucesso para ‘nome’.

Pode usar o nome lido neste ponto à vontade.
*/
}
else if(p<ultimo || *q=='\0'){
/*
Nome truncado por interrupção prematura da leitura em fgets(),
antes de ler ‘sizeof nome’ (que é o mesmo que
‘sizeof nome_mais_lf-1’) caracteres.
*/
if(ferror(stdin)){
/*
Trata erro de leitura. Pode ser perigoso considerar o
nome lido como válido.
*/
}
else{
/*
Trata fim de arquivo. Tratar o nome como válido pode ser
aceitável ou não, dependendo da aplicação.
*/
}
}
else{
/*
Usuário digitou nome grande demais, e um dos caracteres
excedentes acabou sendo consumido por fgets() e guardado
em ‘nome_mais_lf’, mas não há espaço para ele em ‘nome’.

É possível devolver o caráter consumido a mais para o buffer
de entrada, fazendo “ungetc(*q, stdin)”, mas possivelmente
você vai preferir descartá-lo junto com os demais caracteres
excedentes que porventura ainda estejam no buffer de entrada,
e tentar uma nova leitura de um nome não truncado mais tarde.
*/
}
}


Já se você topar uma implementação em mais baixo nível, eis uma função feita sob medida para você, evitando o custo de chamar strlen() e qualquer cópia entre arrays.

	char *const ultimo=nome+sizeof nome-1;
char *p=nome;
int ch;

// Pula espaços em branco no início da linha.
while(isspace(ch=getchar()))
;
if(ch==EOF)
goto trata_erros;

*ultimo='\0';
for(p=nome; p<ultimo; p++)
switch(ch=getchar()){
case EOF:
goto trata_erros;
case '\n':
*p='\0';
goto saida;
default:
*p=ch;
}
/*
Chegou ao fim do loop mas ainda não encontrou marca de fim de linha.
Pode ser, porém, que ela seja o próximo caráter, então tenta ler mais
um, e vê se é fim de linha ou não.
*/
ch=getchar();
if(ch==EOF)
goto trata_erros;
if(ch!='\n'){
/*
Usuário digitou um nome grande demais.

É possível devolver o caráter consumido a mais por este último
getchar() para o buffer de entrada fazendo “ungetc(ch, stdin)”,
mas possivelmente você vai preferir descartá-lo junto com os
demais caracteres excedentes que porventura ainda estejam no
buffer de entrada, e tentar uma nova leitura de um nome não
truncado mais tarde.
*/
}
goto saida;

trata_erros:
if(p>nome){
/*
Conseguiu ler pelo menos alguns caracteres do nome.
*/
if(ferror(stdin)){
/*
Trata erro de leitura. Pode ser perigoso considerar o
nome lido como válido.
*/
}
else{
/*
Trata fim de arquivo. Tratar o nome como válido pode ser
aceitável ou não, dependendo da aplicação.
*/
}
}
else{
/*
O erro de leitura ou o fim dos dados ocorreu antes de ler qualquer
parte do nome.
*/
if(ferror(stdin)){
/* Trata erro de leitura. */
}
else{
/* Trata fim de arquivo. */
}
}

saida:







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts