Ir ao conteúdo

Posts recomendados

Postado

Olá, boa tarde e boa sexta-feira. Estou fazendo um código para registrar alguns atletas que desejam fazer parte do time de futebol da minha sala. No entanto, não estou conseguindo fazer a opção para aparecer uma lista com as pessoas que se inscreveram. Alguém pode me ajudar?

 

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

typedef struct {
  char nome[20];
  int matricula;
  int idade;
  float peso;
  float altura;
  char posicao[100];
  int operacao;
}
play;

play cadastra_play() {

  play a;
  printf("Digite o seu nome: \n");
  scanf(" %[^\n]", a.nome);
  printf("Digite sua matricula: \n");
  scanf("%d", & a.matricula);
  printf("Digite sua idade: \n");
  scanf("%d", & a.idade);
  printf("Digite seu peso: \n");
  scanf("%f", & a.peso);
  printf("Digite sua altura: \n");
  scanf("%f", & a.altura);
  printf("Digite a posicao que voce pretende jogar: ");
  scanf("%s", & a.posicao);
  printf("\n");
  printf("Obrigado pelo cadastro");
  sleep(2);
  return a;
}

play * insere_play(play * v, int * n, play novo) {
  v = (play * ) realloc(v, ( * n + 1) * sizeof(play));
  if (v == 0) {
    printf("Ops! não estamos conseguindo inserir o aluno");
  }
  v[ * n] = novo;
  ( * n) ++;
  return v;

}

play * remove_play(play * v, int * n, int matricula) {
  for (int i = 0; i < * n; i++) {
    if (v[i].matricula == matricula) {
      v[i] = v[ * n - 1];
      v = (play * ) realloc(v, ( * n - 1) * sizeof(play));
      if (v == 0) {
        printf("Ops! não foi possivel remover alunos");
        return 0;
      }
      ( * n) --;
      break;
    }
  }
  return v;
}

int main() {
  int num_oper = 0, i, n = 0;
  play * v = 0;
  int mat;

  char oper = 0;
  while (oper != 'S') {
    system("cls");
    printf("===MENU=== \n");
    printf("Escolha: I... Cadastrar Aluno\nR: Remove Aluno\nS: Sair do programa \n");
    scanf(" %c", & oper);
    switch (oper) {
    case 'I':
      ;
      play novo = cadastra_play();
      insere_play(v, & n, novo);
      break;
    case 'R':
      scanf("%d\n", & mat);
      v = remove_play(v, & n, mat);
      break;
    case 'L':
      //inserir para listar 
    case 'S':
      exit(1);
      break;
    default:
      printf("opcao invalida");
      break;
    }
  }

  for (i = 0; i < n; i++)
    printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome, v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);

  free(v);

  return 0;
}

 

Postado

Eu acho que é porque você colocou um exit(1) pra sair.
Ai nesse caso, ele termina o programa de uma vez, sem passar pelo laço for.

acho que você podia colocar ope='s' pra sair do while e ler o laço final

Além disso, acho que sua função insere retorna valor... não devia ser algo mais ou menos assim:

v = insere()

Postado
4 minutos atrás, codigo rápido disse:

Eu acho que é porque você colocou um exit(1) pra sair.
Ai nesse caso, ele termina o programa de uma vez, sem passar pelo laço for.

acho que você podia colocar ope='s' pra sair do while e ler o laço final

Eu alterei esse exit e criei uma função para listar pessoas, mas mesmo assim ainda não vai :(

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

typedef struct {
  char nome[20];
  int matricula;
  int idade;
  float peso;
  float altura;
  char posicao[100];
  int operacao;
}
play;

play cadastra_play() {

  int num_oper = 0;
  play a;
  do {
    printf("Digite o seu nome: \n");
    scanf(" %[^\n]", a.nome);
    printf("Digite sua matricula: \n");
    scanf("%d", & a.matricula);
    printf("Digite sua idade: \n");
    scanf("%d", & a.idade);
    printf("Digite seu peso: \n");
    scanf("%f", & a.peso);
    printf("Digite sua altura: \n");
    scanf("%f", & a.altura);
    printf("Digite a posicao que voce pretende jogar: \n");
    scanf(" %[^\n]", a.posicao);

    printf("Deseja cadastrar mais aluno? (1 - para sim e 2- para não )\n");
    scanf("%d", & num_oper);
    system("cls");
  } while (num_oper == 1);

  printf("\n");
  return a;
}

play * insere_play(play * v, int * n, play novo) {
  v = (play * ) realloc(v, ( * n + 1) * sizeof(play));
  if (v == 0) {
    printf("Ops! não estamos conseguindo inserir o aluno");
  }
  v[ * n] = novo;
  ( * n) ++;
  return v;

}

play * remove_play(play * v, int * n, int matricula) {
  for (int i = 0; i < * n; i++) {
    if (v[i].matricula == matricula) {
      v[i] = v[ * n - 1];
      v = (play * ) realloc(v, ( * n - 1) * sizeof(play));
      if (v == 0) {
        printf("Ops! não foi possivel remover alunos");
        return 0;
      }
      ( * n) --;
      break;
    }
  }
  return v;
}
//______________________________________
play * lista_play(play * v, int * n) {
  printf("\nSegue a lista de alunos cadastrados por ordem de cadastro: ");
  for (int i = 0; i < n; i++) {
    printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome, v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);
  }
}
//_____________________________________________
int main() {
  int i, n = 0;
  play * v = 0;
  int mat;
  printf("===MENU=== \n");
  char oper = 0;
  while (oper != 'S') {
    printf("Escolha:\nI... Cadastrar Aluno\nR... Remove Aluno\nL... Listar alunos \n");
    scanf(" %c", & oper);
    system("cls");
    switch (oper) {
    case 'I':
      ;
      play novo = cadastra_play();
      insere_play(v, & n, novo);
      break;
    case 'R':
      v = remove_play(v, & n, mat);
      break;
    case 'L':
      v = lista_play(v, & n);
    case 'S':
    	 system("exit");
    default:
      printf("opcao invalida");
      break;
    }
  }

  //for (i = 0; i < n; i++)
  //printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome,v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);   

  free(v);

  return 0;
}

 

  • Curtir 1
Postado
5 minutos atrás, Talyson Maia disse:
play cadastra_play() {

  int num_oper = 0;
  play a;
  do {

 

Você está retornando uma variável local à função. Ela deixa de existir quando você retorna...

 

Não escreva assim. Ou retorna um play ou recebe um.

 

Sobre seu programa:

  • teste sempre o retorno de scanf(). Não tem sentido seguir se não leu nada.
  • não escreva um programa interativo de início. Use constantes ou funções factory que retornam exemplos
  • main() deve ser a primeira função de seu programa, se possível em um arquivo separado

 

 

  • Confuso 1
Postado
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

typedef struct 
{
	char nome[20];
	int matricula;
	int idade;
	float peso;
	float altura;
	char posicao[100];
	int operacao;
}play;

play cadastra_play() 
{
	play a;
	printf("Digite o seu nome: \n");
	scanf(" %[^\n]", &a.nome);
	printf("Digite sua matricula: \n");
	scanf("%d", &a.matricula);
	printf("Digite sua idade: \n");
	scanf("%d", &a.idade);
	printf("Digite seu peso: \n");
	scanf("%f", &a.peso);
	printf("Digite sua altura: \n");
	scanf("%f", &a.altura);
	printf("Digite a posicao que voce pretende jogar: ");
	scanf("%s", &a.posicao);
	printf("\n");
	printf("Obrigado pelo cadastro\n");
	//sleep(2);
	return a;
}

play * insere_play(play * v, int * n, play novo) 
{
	v = (play * ) realloc(v, ( * n + 1) * sizeof(play));
	if (v == 0) 
	{
		printf("Ops! não estamos conseguindo inserir o aluno");
	}
	v[ * n] = novo;
	( * n) ++;
	return v;

}

play * remove_play(play * v, int * n, int matricula) 
{
	for (int i= 0; i<*n; i++) 
	{
		if (v[i].matricula == matricula) 
		{
			v[i] = v[ * n - 1];
			v = (play * ) realloc(v, ( * n - 1) * sizeof(play));
			if (v == 0) 
			{
				printf("Ops! não foi possivel remover alunos");
				return 0;
			}
			( * n) --;
			break;
		}
	}
	return v;
}

int main() 
{
	int num_oper = 0, n = 0;
	play * v;
	int mat;

	char oper = 0;
	while (oper != 'S') 
	{
		system("cls");
		printf("===MENU=== \n");
		printf("Escolha: I... Cadastrar Aluno\nR: Remove Aluno\nS: Sair do programa \n");
		scanf(" %c", & oper);
		switch (oper) 
		{
			case 'I':
				;
				play novo = cadastra_play();
				v = insere_play(v, &n, novo);
				break;
			case 'R':
				scanf("%d\n", & mat);
				v = remove_play(v, & n, mat);
				break;
			case 'L':
				//inserir para listar 
			case 'S':
				oper='S';
				break;
			default:
				printf("opcao invalida");
		}
	}

	for (int i=0; i<n; i++)
	{
		printf("%s\n%d\n%d\n%.1f\n%.2f%s\n", v[i].nome, v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);
	}
	free(v);
	return 0;
}

 

O meu ficou assim e funcionou.

 

Olhando bem, acho que você nem precisa desse case 'S' porque oper, dentro do while também, já vai ser S.

Bastava apenas por um break dentro do case S.

  • Amei 1
Postado

@codigo rápido O meu continua sem lsitar, eu fiz algumas mudanças (coloquei uma função para listar) e na saída fiz aquilo que voce colocou no seu código. O meu roda normal, mas não lista. voce poderia conferir? Por favor

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

typedef struct {
  char nome[20];
  int matricula;
  int idade;
  float peso;
  float altura;
  char posicao[100];
  int operacao;
}
play;

play cadastra_play() {

  int num_oper = 0;
  play a;
  do {
    printf("Digite o seu nome: \n");
    scanf(" %[^\n]", a.nome);
    printf("Digite sua matricula: \n");
    scanf("%d", & a.matricula);
    printf("Digite sua idade: \n");
    scanf("%d", & a.idade);
    printf("Digite seu peso: \n");
    scanf("%f", & a.peso);
    printf("Digite sua altura: \n");
    scanf("%f", & a.altura);
    printf("Digite a posicao que voce pretende jogar: \n");
    scanf(" %[^\n]", a.posicao);

    printf("Deseja cadastrar mais aluno? (1 - para sim e 2- para não )\n");
    scanf("%d", & num_oper);
    system("cls");
  } while (num_oper == 1);

  printf("\n");
  return a;
}

play * insere_play(play * v, int * n, play novo) {
  v = (play * ) realloc(v, ( * n + 1) * sizeof(play));
  if (v == 0) {
    printf("Ops! não estamos conseguindo inserir o aluno");
  }
  v[ * n] = novo;
  ( * n) ++;
  return v;

}

play * remove_play(play * v, int * n, int matricula) {
  for (int i = 0; i < * n; i++) {
    if (v[i].matricula == matricula) {
      v[i] = v[ * n - 1];
      v = (play * ) realloc(v, ( * n - 1) * sizeof(play));
      if (v == 0) {
        printf("Ops! não foi possivel remover alunos");
        return 0;
      }
      ( * n) --;
      break;
    }
  }
  return v;
}
//______________________________________
play * lista_play(play * v, int * n) {
  printf("\nSegue a lista de alunos cadastrados por ordem de cadastro: ");
  for (int i = 0; i < n; i++) {
    printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome, v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);
  }
}
//_____________________________________________
int main() {
  int i, n = 0;
  play * v = 0;
  int mat;
  printf("===MENU=== \n");
  char oper = 0;
  while (oper != 'S') {
    printf("Escolha:\nI... Cadastrar Aluno\nR... Remove Aluno\nL... Listar alunos \n");
    scanf(" %c", & oper);
    system("cls");
    switch (oper) {
    case 'I':;
      play novo = cadastra_play();
      v = insere_play(v, & n, novo);
      break;
    case 'R':
      v = remove_play(v, & n, mat);
      break;
    case 'L':
      v = lista_play(v, & n);
    case 'S':
    	 oper='S';
		break;
    default:
      printf("opcao invalida");
      break;
    }
  }

  for (i = 0; i < n; i++)
  printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome,v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);   

  free(v);

  return 0;
}

 

Postado
18 minutos atrás, Talyson Maia disse:
    case 'L':
      v = lista_play(v, & n);
    case 'S':
    	 system("exit");
    default:


Assim ficou mais elegante. Mas no caso de listar, não retorna valor... ela só imprime. A lista, é só um metodo. Ela não e funcao. Então não pode ser v=lista...

tem que ser apenas lista_play()

Postado
12 minutos atrás, arfneto disse:

 

Você está retornando uma variável local à função. Ela deixa de existir quando você retorna...

 

Não escreva assim. Ou retorna um play ou recebe um.

 

Sobre seu programa:

  • teste sempre o retorno de scanf(). Não tem sentido seguir se não leu nada.
  • não escreva um programa interativo de início. Use constantes ou funções factory que retornam exemplos
  • main(0 deve ser a primeira função de seu programa, se possível em um arquivo separado

 

 

A variavel play? não entendi bem

Postado
3 minutos atrás, codigo rápido disse:
return a;

 

@codigo rápidocomo eu disse, não pode retornar uma variável local. Comentar o sleep() não muda muito.

 

@Talyson Maia Escreva em torno dos dados. Falta um nível para compor as coisas/ É muito mais fácil se você escrever

algo assim, escolhendo uma das 3 opções:

typedef struct
{
    char  nome[20];
    int   matricula;
    int   idade;
    float peso;
    float altura;
    char  posicao[100];
    int   operacao;

}   Play;


typedef struct
{
    unsigned N;
    Play     play[20];

}   Players_A;
 

typedef struct
{
    unsigned N;
    Play*    play;

}   Players_B;


typedef struct
{
    Play**     play; // NULL terminated

}   Players_C;

 

Sobre as opções: 

 

  • Seus dados são um conjunto de players. Assim é mais fácil tratar como tal. Encapsulamento.
  • Players_A  tem um vetor de certa capacidade
  • Players_B Tem um vetor deles que você vai alocando
  • Players_C tem um vetor de players com um NULL no final, como se fosse uma string
  • Em todos os casos você pode usar as funções passando o endereço de uma estrutura dessas, os players e não um cara só. E assim pode mudar o conteúdo sem mudar o container... 
  • E inserir claro que é mais simples se você escrever
        int    cadastra_player( Play* um_cara, Players* grupo);
  • em todos os casos retorne um int com 0 para sucesso. Esse é o absoluto comum em C.

 

Postado

@arfneto Não consegui compreender essa explicação, acho que é muito complexo para eu fazer dessa forma. Vou tentar estudar mais um pouco esse modelo que você mandou e aplicar no meu código. Eu realmente não entendi, mas agradeço muito

Postado
20 horas atrás, Talyson Maia disse:

muito complexo para eu fazer dessa forma.

Talyson! calma ai... eu te respondo.

quando você ver um return dentro da função, é porque ela retorna um valor. por isso ela é chamada função.... como na matematica. existe função f(x) que é funcao porque retorna valor.

A diretenca de metodo pra função é apenas isso. Ambas fazem alguma coisa. Elas trabalham, imprimem, calculam... todas são metodos por isso. Mas o que diferencia o metodo de funçao é que função retorna um valor. esse valor é retornado quando você ve um return dentro do metodo.

E esse foi um dos motivo de não ver a lista:
v não tava recebendo valor novo;
você colocado um exit antes de ler o print da sua lista.

fora isso, tá tudo bonitinho, ainda mais pra quem tá começando.

Postado

@Talyson Maia Que forma? Eu te mostrei 3 opções. E as 3 são mais simples de usar do que do modo como está fazendo. 

 

E vai dar mais trabalho de fazer como está fazendo. E nem está funcionando, talvez por isso mesmo.

 

O que é complexo?

 

Veja um uso disso:

 

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

typedef struct
{
    char  nome[20];
    int   matricula;
    int   idade;
    float peso;
    float altura;
    char  posicao[100];
    int   operacao;

} Play;

typedef struct
{
    unsigned N;
    unsigned limite;
    Play     play[20];

} Players;

// o simples: cadastra 'um' em 'todos' e retorna zero se deu certo
int         cadastra_play(Play* um, Players* todos);

// o simples: insere 'um' em 'todos'
int         insere_play(Play* v, Players* grupo);

// igual: remove o jogador do grupo de jogadores
int         remove_play(Play* v, Players* grupo);


int         main(void)
{
    Players grupo;
    grupo.N = 0;
    grupo.limite = 20;

    return 0;
}

int cadastra_play(Play* um, Players* todos)  { return 0; };
int insere_play(Play* um,   Players * grupo) { return 0; };
int remove_play(Play* um,   Players * grupo) { return 0; };

/*
https: //www.clubedohardware.com.br/forums/topic/
1557604-listar-pessoas-que-se-inscreveram-sistema/
*/

 

É o comum em C. 

 

E como eu disse, é comum porque é melhor escrever assim. Desse modo por exemplo não precisa controlar o tamanho porque já está dentro do grupo. E pode mudar o jogador sem mexer nas funções que tratam o grupo. 

 

 

 

 

@codigo rápido atente para o que eu disse: a função retorna uma variável local e o programa vai cancelar em seguida, o dele o meu ou o seu. está errado e comentar aquilo não ajudou em nada. 

Postado
1 hora atrás, codigo rápido disse:

A diretenca de metodo pra função é apenas isso. Ambas fazem alguma coisa. Elas trabalham, imprimem, calculam... todas são metodos por isso. Mas o que diferencia o metodo de funçao é que função retorna um valor. esse valor é retornado quando você ve um return dentro do metodo

 

Essa distinção não existe em C, ou C++ ou C#, as linguagens neste forum. Uma função nessa linguagem é uma função. Só isso. Uma função void tem um return sem parâmetro.

 

Essa distinção existe em Pascal, que tem procedure e function, E Visual Basic por exemplo, que tem Sub e Function.

 

Em C isso não existe. Nem em C++, nem em C#. Apenas function. Em C++ existe a descrição usual método, que é uma função em uma classe, ao contrário de uma free function, que é uma função avulsa, que não está associada a uma classe. java por exemplo só tem métodos, functions.

 

 

1 hora atrás, codigo rápido disse:

fora isso, tá tudo bonitinho, ainda mais pra quem tá começando

 

@Talyson MaiaAtente para o fato de que não pode retornar a em cadastra_play():
 

    return a;


é uma variável local e vai cancelar seu programa logo mais. O exemplo no tópico #6 tem o mesmo erro.

 

Talvez te ajude a entender vendo um exemplo do comum:

 

 

 

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

typedef struct
{
    char  nome[20];
    int   matricula;
    int   idade;
    float peso;
    float altura;
    char  posicao[100];
    int   operacao;

} Play;

typedef struct
{
    unsigned N;
    unsigned limite;
    Play     play[20];

} Players;

// o simples: cadastra 'um' em 'todos' e retorna zero se deu certo
int         cadastra_play(Play* um, Players* todos);

// o simples: insere 'um' em 'todos'
int         insere_play(Play* v, Players* grupo);

// igual: remove o jogador do grupo de jogadores
int         remove_play(Play* v, Players* grupo);

void  mostra_um(Play*); // so para mostrar um jogador
Play* fabrica();

int         main(void)
{
    Players grupo;
    grupo.N = 0;
    grupo.limite = 20;

    // agora insere jogadores em 'grupo' ate dar erro
    // que vai ser quando encher...
    int res = 0;
    printf("Grupo tem %d de %d jogadores possiveis\n\n", grupo.N, grupo.limite);

    do {
        Play* um = fabrica(); // inventa um
        printf( "%d ", um->matricula);
        res      = insere_play(um, &grupo);
        free(um);
    } while (res == 0);
    printf( "\n\
Erro ao inserir: grupo tem %d jogadores de %d possiveis.\n",
        grupo.N, grupo.limite);

    // agora mostra os caras 
    printf(
        "grupo com %d de %d\n\tnome(idade) matricula, posicao\n",
        grupo.N, grupo.limite);
    for (unsigned i = 0; i < grupo.N; i += 1) mostra_um(&grupo.play[i]);
    return 0;
}

int cadastra_play(Play* um, Players* todos)  { return 0; };

int insere_play(Play* um,   Players * grupo)
{ 
    if (grupo->N == grupo->limite) return -1; // não cabe
    grupo->play[grupo->N] = *um; // copia simples
    grupo->N += 1;
    return 0;
};

int remove_play(Play* um,   Players * grupo) { return 0; };

/*
https: //www.clubedohardware.com.br/forums/topic/
1557604-listar-pessoas-que-se-inscreveram-sistema/
*/

// cria registros de jogadores preenchidos e numerados
// com valores conhecidos:
// nome a partir de Jogador N0001
Play* fabrica()
{ 
    static int prim = 1; // para numerar os caras
    char       nome[20];
    Play* um = (Play*)malloc(sizeof(Play));
    sprintf(nome, "Jogador N%04d", prim);
    strcpy(um->nome, nome);
    um->matricula = prim;
    um->idade     = 18 + prim % 40;
    um->peso      = 50.f + prim % 20;
    um->altura    = 1.5f + prim % 65;
    sprintf(nome, "Posicao P%04d", prim);
    strcpy(um->posicao, nome);
    um->operacao = 1000 + prim;
    prim += 1;
    return um;
}


void mostra_um(Play* p)
{
    printf(
        "%20s (%d): Matr. %2d, Pos: \"%20s\"\n", p->nome, p->idade,
        p->matricula, p->posicao);
    return;
};

 

Esse programa mostra como escrever um programa não-interativo e começar a testar em minutos.

 

 

Eis a saída:

Grupo tem 0 de 20 jogadores possiveis

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Erro ao inserir: grupo tem 20 jogadores de 20 possiveis.
grupo com 20 de 20
        nome(idade) matricula, posicao
       Jogador N0001 (19): Matr.  1, Pos: "       Posicao P0001"
       Jogador N0002 (20): Matr.  2, Pos: "       Posicao P0002"
       Jogador N0003 (21): Matr.  3, Pos: "       Posicao P0003"
       Jogador N0004 (22): Matr.  4, Pos: "       Posicao P0004"
       Jogador N0005 (23): Matr.  5, Pos: "       Posicao P0005"
       Jogador N0006 (24): Matr.  6, Pos: "       Posicao P0006"
       Jogador N0007 (25): Matr.  7, Pos: "       Posicao P0007"
       Jogador N0008 (26): Matr.  8, Pos: "       Posicao P0008"
       Jogador N0009 (27): Matr.  9, Pos: "       Posicao P0009"
       Jogador N0010 (28): Matr. 10, Pos: "       Posicao P0010"
       Jogador N0011 (29): Matr. 11, Pos: "       Posicao P0011"
       Jogador N0012 (30): Matr. 12, Pos: "       Posicao P0012"
       Jogador N0013 (31): Matr. 13, Pos: "       Posicao P0013"
       Jogador N0014 (32): Matr. 14, Pos: "       Posicao P0014"
       Jogador N0015 (33): Matr. 15, Pos: "       Posicao P0015"
       Jogador N0016 (34): Matr. 16, Pos: "       Posicao P0016"
       Jogador N0017 (35): Matr. 17, Pos: "       Posicao P0017"
       Jogador N0018 (36): Matr. 18, Pos: "       Posicao P0018"
       Jogador N0019 (37): Matr. 19, Pos: "       Posicao P0019"
       Jogador N0020 (38): Matr. 20, Pos: "       Posicao P0020"

 

Cirando as funções como eu expliquei é o comum. Veja os protótipos:

 

// o simples: cadastra 'um' em 'todos' e retorna zero se deu certo
int         cadastra_play(Play* um, Players* todos);
// o simples: insere 'um' em 'todos'
int         insere_play(Play* v, Players* grupo);
// igual: remove o jogador do grupo de jogadores
int         remove_play(Play* v, Players* grupo);

 

Então em main() pode inserir até dar erro:
 

    Players grupo;
    grupo.N = 0;
    grupo.limite = 20;

    // agora insere jogadores em 'grupo' ate dar erro
    // que vai ser quando encher...
    int res = 0;
    printf("Grupo tem %d de %d jogadores possiveis\n\n", grupo.N, grupo.limite);

    do {
        Play* um = fabrica(); // inventa um
        printf( "%d ", um->matricula);
        res      = insere_play(um, &grupo);
        free(um);
    } while (res == 0);

 

Entenda a vantagem:

  • insere() insere algo em algum lugar, o óbvio: um player no grupo de players e retorna zero se deu certo
  • fabrica() devolve um player totalmente preenchido e numeradinho, de modo que pode inserir e apagar em seguida.
  • compare isso o com o tempo que você levaria para inserir 20 caras respondendo a todos aqueles prompts e digitando valores para SETE campos por jogador, 140 deles.
  • a primeira função que deia ter escrito seria a que lista os caras, porque ela tem que funcionar mesmo que não tenha nenhum na lista
  • o que importa é ter dados para testar logo
  • programas escritos assim em torno dos dados muitas vezes rodam certinhos logo na primeira vez. É o que se chama de correto por construçao.
  • os dados de player ficam dentro de Player, os do conjunto ficam dentro do Players e você pode tratar como unidade. Esse é o conceito de encapsulamento. Um nome chique para explicar a embalagem por atacado dos dados.

Exemplo
 

void mostra_um(Play* p)
{
    printf(
        "%20s (%d): Matr. %2d, Pos: \"%20s\"\n", p->nome, p->idade,
        p->matricula, p->posicao);
    return;
};

 

Essa função mostra um jogador na tela. Podia ter cores, ter todos os 7 campos, ter bordas, não faz diferença. Mas se ela existe você pode usar
 

    for (unsigned i = 0; i < grupo.N; i += 1) mostra_um(&grupo.play[i]);

 

Para mostrar todos os caras em uma linha de comando. E se mudar o jeito de imprimir não mexe nessa parte. Esse é o conceito encapsulamento. E entra apenas um ponteiro para Player, então não depende do conteúdo

 

E uma função assim
 

void mostra_todos(Players* G)
{   // agora mostra os caras
    printf(
        "Grupo com %d de %d\n\tnome(idade) matricula, posicao\n",
        G->N, G->limite);
    for (unsigned i = 0; i < G->N; i += 1) mostra_um(&G->play[i]);

    return; 
};

 

Permitiria usar main() assim:
 

int         main(void)
{
    Players grupo;
    grupo.N = 0;
    grupo.limite = 20;

    int res = 0;
    printf("Grupo tem %d de %d jogadores possiveis\n\n", grupo.N, grupo.limite);

    do {
        Play* um = fabrica(); // inventa um
        printf( "%d ", um->matricula);
        res      = insere_play(um, &grupo);
        free(um);
    } while (res == 0);
    printf( "\n\
Erro ao inserir: grupo tem %d jogadores de %d possiveis.\n",
        grupo.N, grupo.limite);

    mostra_todos(&grupo);
    return 0;
}

 

E tem a vantagem de ser mais legível, com apenas 20 linhas onde insere até dar erro, e mostra que o grupo está lotado. E você já está testando o programa com dados completos.

 

 

  • Curtir 1
  • Amei 1
Postado

@arfneto Cara, eu me sinto tão burro vendo sua explicação. Você me deu uma faca e queijo na mão e mesmo assim não estou conseguindo aplicar. Estou há um tempão quebrando a cabeça com esse código, desde ontem a noite. Eu agradeço muito pela sua atenção

@codigo rápido AAA, eu consegui fazer a parte de listar e excluir. Agora o único problema é que quando eu faço mais de dois cadastros, ele só lista uma pessoa.

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

typedef struct {
  char nome[20];
  int matricula;
  int idade;
  float peso;
  float altura;
  char posicao[100];
  int operacao;
}
play;

play cadastra_play() {

  int num_oper = 0;
  play a;
  do {
    printf("Digite o seu nome: \n");
    scanf(" %[^\n]s", a.nome);
    printf("Digite sua matricula: \n");
    scanf("%d", &a.matricula);
    printf("Digite sua idade: \n");
    scanf("%d", &a.idade);
    printf("Digite seu peso: \n");
    scanf("%f", &a.peso);
    printf("Digite sua altura: \n");
    scanf("%f", &a.altura);
    printf("Digite a posicao que voce pretende jogar: \n");
    scanf(" %[^\n]s", a.posicao);

    printf("Deseja cadastrar mais aluno? (1 - para sim e 2- para não )\n");
    scanf("%d", & num_oper);
    system("cls");
  } while (num_oper == 1);

  printf("\n");
  return a;
}
play * insere_play(play *v, int *n, play novo) {
  v = (play*) realloc(v, (*n + 1) * sizeof(play));
  if (v == 0) {
    printf("Ops! não estamos conseguindo inserir o aluno");
  }
  v[*n] = novo;
  (*n)++;
  return v;
}

play *remove_play(play *v, int *n, int matricula) {
  for (int i = 0; i < *n; i++) {
    if (v[i].matricula == matricula) { // 1 2 3 4 | 1 3 3 4 | 1 3 4 4 | 1 3 4
      for(int j = i; j < *n - 1; j++) {
        v[j] = v[j+1];
      }
      v = (play*) realloc(v, (*n - 1) * sizeof(play));
      if (v == 0) {
        printf("Ops! não foi possivel remover alunos");
        return 0;
      }
      (*n)--;
      break;
    }
  }
  return v;
}
//______________________________________
void lista_play(play *v, int *n) {
  printf("\nSegue a lista de alunos cadastrados por ordem de cadastro: ");
  for (int i = 0; i < *n; i++) {
    printf("\n%s\n%d\n%d\n%.1f\n%.2f\n%s\n", v[i].nome, v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);
  }
}
//_____________________________________________
int main() {
  int i, n = 0;
  play *v = 0, x;
  int mat = 0;
  printf("===MENU=== \n");
  //system("cls");
  char oper = 0;
  while (oper != 'S') {
    printf("Escolha:\nI... Cadastrar Aluno\nR... Remove Aluno\nL... Listar alunos \n");
    scanf(" %c", & oper);
    system("cls");
    switch (oper) {
    case 'I':
      ;
      play novo = cadastra_play();
      v = insere_play(v, &n, novo);
      break;
    case 'R':
      scanf("%d", &mat);
      v = remove_play(v, &n, mat);
      break;
    case 'L':
      lista_play(v, & n);
    case 'S':
        system("exit");
        break;
    default:
      printf("opcao invalida");
      break;
    }
  }

  //for (i = 0; i < n; i++)
  //printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome,v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);   

  free(v);

  return 0;
}

 

Postado

 

29 minutos atrás, Talyson Maia disse:

eu consegui fazer a parte de listar e excluir. Agora o único problema é que quando eu faço mais de dois cadastros, ele só lista uma pessoa.

 

eu testei aqui o mesmo codigo que te passei. Pra mim mostrou os 2 que cadastrei.
você mudou algo e não percebeu...

29 minutos atrás, Talyson Maia disse:

Cara, eu me sinto tão burro vendo sua explicação. Você me deu uma faca e queijo na mão e mesmo assim não estou conseguindo aplicar.

Não se sinta. no começo é assim mesmo.

já pegou cada função dessas que está utilizando no seu programa e testou, sozinho em programas menores? a gente começa com o printf, depois vai pro scanf... depois ponteiros, malloc, realoc e etc... A gente só começa programando algo assim quando a gente já tá crack em todos os metodos que pretende utilizar. A ideoa é dividir pra conquistar.


 

Postado

Olha só:

 

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

typedef struct 
{
  char nome[20];
  int matricula;
}
play;

play cadastra_play() 
{
  int num_oper = 0;
  play a;

    // do { Se colocar esse loop aqui, ele renova play a antes dele ser inserino no array
    printf("Digite o seu nome: \n");
    scanf(" %[^\n]s", a.nome);
    printf("Digite sua matricula: \n");
    scanf("%d", &a.matricula);
    //printf("Deseja cadastrar mais aluno? (1 - para sim e 2- para não )\n");
    //scanf("%d", & num_oper);
    system("cls");
  //} while (num_oper == 1);

  printf("\n");
  return a;
}


play * insere_play(play *v, int *n, play novo) 
{
  v = (play*) realloc(v, (*n + 1) * sizeof(play));
  if (v == 0) {
    printf("Ops! não estamos conseguindo inserir o aluno");
  }
  v[*n] = novo;
  (*n)++;
  return v;
}


play *remove_play(play *v, int *n, int matricula) 
{
  for (int i = 0; i < *n; i++) {
    if (v[i].matricula == matricula) {
      for(int j = i; j < *n - 1; j++) {
        v[j] = v[j+1];
      }
      v = (play*) realloc(v, (*n - 1) * sizeof(play));
      if (v == 0) {
        printf("Ops! não foi possivel remover alunos");
        return 0;
      }
      (*n)--;
      break;
    }
  }
  return v;
}


//______________________________________
void lista_play(play *v, int *n) 
{
  printf("\nSegue a lista de alunos cadastrados por ordem de cadastro: ");
  for (int i=0; i<*n; i++) 
  {
    printf("\n%s\n%d\n", v[i].nome, v[i].matricula);
  }
}
//_____________________________________________


int main() 
{
  int i, n = 0;
  play *v = 0;
  int mat = 0;
  printf("===MENU=== \n");
  //system("cls");
  char oper = 0;
  while (oper != 'S') 
  {
    printf("Escolha:\nI... Cadastrar Aluno\nR... Remove Aluno\nL... Listar alunos \n");
    scanf(" %c", & oper);
    system("cls");
    switch (oper) 
    {
	    case 'I':
		;
	      play novo = cadastra_play();
	      v = insere_play(v, &n, novo);
	      break;
	    case 'R':
	      scanf("%d", &mat);
	      v = remove_play(v, &n, mat);
	      break;
	    case 'L':
	      lista_play(v, &n);
	      break;
	    case 'S':
	      break;
	    default:
	      printf("opcao invalida");
	      break;
    }
  }
  free(v);
  return 0;
}

 

 

você colocou um do while dentro do metodo de inserção.
Só que esqueceu que quando de faz um "play a", antes desse loop, não adicionou ainda no array. Isso faz é alterar os valores que já escreveu em a.

Para fazer o que quer, ir adicionando na sequencia, é necessário incluir dentro de cadastra_play o metodo insere_play... ou seja, vai precisar passar parametro para cadastra_play, para que a função insere_play dentro do metodo consiga ver essas variaveis.

acha que consegue fazer? Se não conseguir, avisa que que mostro.

OBS: eu tirei o monte de variaveis apenas pra agilizar aqui, mas você pode corrigir ai do seu modo e gosto.

  • Obrigado 1
Postado
1 hora atrás, arfneto disse:

@Talyson Maia você não faz uma única pergunta. Eu é que não entendo.

 

Notou que aquele exemplo é o seu programa e está funcionando?

 

Devo desistir?

 Não não, você não deve desistir. Sua ajuda ta sendo essencial pra mim, graças a ela eu consegui resumir bem mais o meu código e organizar. O problema é comigo, estou aprendendo c há pouco tempo e fico muito confuso com tudo. Eu agradeço de mais por toda sua ajuda.

@codigo rápido Tentarei fazer isso agora, obrigado. Acho que entendi bem e faz sentido, se o while ficar repetindo ali é claro que vai salvar só uma função kkkk, que vacilo meu

Postado
1 hora atrás, arfneto disse:

Atente para o fato de que não pode retornar a em cadastra_play():
 

 

@Talyson Maia Toda vez que eu disse isso  e foram 3 ao menos) EU estava errado.

 

Essa construção é tão pouco comum que eu li o que é o erro comum. :( 

 

Você pode sim retornar a;

 

Isso não é comum porque cria uma cópia temporária da variável, no caso a struct toda, e pode levar a ainda uma outra cópia, da struct toda, no ponto em que a função foi chamada.

 

Quando você escreve
 

    return a; 

 e a uma nova estrutura é criada, para conter um novo a. E todos os elementos são copiados, e essa variável temporária recebe um endereço e é devolvida ao chamador. E lá acontece outra cópia. 

 

Em 

 

	Player a = cadastra_play();

 

pode ter 2 cópias a toa dos valores da variável local a na função. A solução para isso é o que se chama move semantic como foi incluído em C++ anos atrás, em que o programador pode se precaver em relação a isso. 

 

De todo modo não é provavelmente um tópico para esse assunto aqui. Apenas entenda que funciona como você escreveu. Mas não faça isso em seu emprego ou em seu estágio ;) 

 

Por essa razão o que se faz na prática é retornar um endereço de memória, alocando a estrutura em cadastra_play() mas devolvendo apenas o seu endereço, 4 ou 8 bytes, e atribuindo esse endereço a outra variável em main(), de modo que não há atraso ou desperdício.

 

Me desculpem, @Talyson Maiae @codigo rápido. No entanto o resto continua válido como eu expliquei e seu programa não está bom, ainda que "quase" funcione.

 

Escreva em torno dos dados, como eu disse. E use ponteiros, não escreva programas interativos, e agrupe seus dados. :) 

 

Exemplo: veja essa implementação de remover()

 

Você passa a matricula e o grupo. Se voltou 0 apagou ok. caso contrário um status

 

int         remove_play(const int mat, Players* g)
{
    int n = -1;
    for ( unsigned i=0; i<g->N; i+=1 )
    { // procura o cara com essa matricula
        if (g->play[i].matricula != mat) continue;
        n = i;  // esse e o cara
        break; // achou, sai fora
    }
    if (n < 0) return -1; // não achou o cara
    // entao vai remover o n-esimo
    // todos que vem depois voltam uma casinha
    for (unsigned i = n; i < g->N; i += 1)
        g->play[i] = g->play[i+1];
    g->N -= 1;
    return 0;
};

 

 

E veja um teste
 

    mostra_todos(&grupo);
    printf(
        "inseriu matriculas de 1 a 20: remove a primeira e a ultima\n");
    remove_play(1, &grupo);
    remove_play(20, &grupo);
    mostra_todos(&grupo);
    printf("Tenta remover de 1 a 20:\n");
    for (int mat = 1; mat <= 20; mat += 1) {
        if (remove_play(mat, &grupo) == 0)
            printf("%d ok ", mat);
        else
            printf("%d erro ", mat);
        if (mat % 5 == 0) printf("\n "); // 5 por linha
    }
    printf("\n");
    printf("Grupo ao final:\n");
    mostra_todos(&grupo);

 

Que mostra

inseriu matriculas de 1 a 20: remove a primeira e a ultima
Grupo com 18 de 20
        nome(idade) matricula, posicao
       Jogador N0002 (20): Matr.  2, Pos: "       Posicao P0002"
       Jogador N0003 (21): Matr.  3, Pos: "       Posicao P0003"
       Jogador N0004 (22): Matr.  4, Pos: "       Posicao P0004"
       Jogador N0005 (23): Matr.  5, Pos: "       Posicao P0005"
       Jogador N0006 (24): Matr.  6, Pos: "       Posicao P0006"
       Jogador N0007 (25): Matr.  7, Pos: "       Posicao P0007"
       Jogador N0008 (26): Matr.  8, Pos: "       Posicao P0008"
       Jogador N0009 (27): Matr.  9, Pos: "       Posicao P0009"
       Jogador N0010 (28): Matr. 10, Pos: "       Posicao P0010"
       Jogador N0011 (29): Matr. 11, Pos: "       Posicao P0011"
       Jogador N0012 (30): Matr. 12, Pos: "       Posicao P0012"
       Jogador N0013 (31): Matr. 13, Pos: "       Posicao P0013"
       Jogador N0014 (32): Matr. 14, Pos: "       Posicao P0014"
       Jogador N0015 (33): Matr. 15, Pos: "       Posicao P0015"
       Jogador N0016 (34): Matr. 16, Pos: "       Posicao P0016"
       Jogador N0017 (35): Matr. 17, Pos: "       Posicao P0017"
       Jogador N0018 (36): Matr. 18, Pos: "       Posicao P0018"
       Jogador N0019 (37): Matr. 19, Pos: "       Posicao P0019"
Tenta remover de 1 a 20:
1 erro 2 ok 3 ok 4 ok 5 ok
 6 ok 7 ok 8 ok 9 ok 10 ok
 11 ok 12 ok 13 ok 14 ok 15 ok
 16 ok 17 ok 18 ok 19 ok 20 erro

Grupo ao final:
Grupo com 0 de 20
        nome(idade) matricula, posicao

 

Entende a razão de encapsulamento e ponteiros e tal não ser só frescura? É mais simples e fácil de ler. E a tal factory function é uma "mão na roda" diria minha avó.

 

Testar leva minutos. não tem que ficar digitando, dá certo em geral na primeira vez...

9 minutos atrás, Talyson Maia disse:

O problema é comigo, estou aprendendo c há pouco tempo e fico muito confuso com tudo. Eu agradeço de mais por toda sua ajuda

 

🤔 O que me deixa confuso é você ficar confuso e não fazer uma única pergunta

  • Obrigado 1
Postado
2 horas atrás, Talyson Maia disse:

@codigo rápido Tentarei fazer isso agora, obrigado. Acho que entendi bem e faz sentido, se o while ficar repetindo ali é claro que vai salvar só uma função kkkk, que vacilo meu

 

você quis dizer: vai salvar só um aluno.



Sim. É isso mesmo.
Sucesso pra você

  • Obrigado 1
Postado

@codigo rápido Uhuu, eu consegui fazer com que aparecesse todos no listar :D
Mas ficou algo meio feio, porquê tipo: quando eu listo os atletas o menu também aparece. Lá no cadastro e no remover o menu não aparece, somente na parte de listar alunos. Sabe o porquê?

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

typedef struct {
  char nome[20];
  int matricula;
  int idade;
  float peso;
  float altura;
  char posicao[100];
  int operacao;
}
play;

play cadastra_play() {
    play a;
    printf("Digite o seu nome: \n");
    scanf(" %[^\n]s", a.nome);
    printf("Digite sua matricula: \n");
    scanf("%d", &a.matricula);
    printf("Digite sua idade: \n");
    scanf("%d", &a.idade);
    printf("Digite seu peso: \n");
    scanf("%f", &a.peso);
    printf("Digite sua altura: \n");
    scanf("%f", &a.altura);
    printf("Digite a posicao que voce pretende jogar: \n");
    scanf(" %[^\n]s", a.posicao);
    system("cls");
    printf("\n");
    printf("Obrigado pelo cadastro. Agora voce retornara ao menu principal.\n");
    sleep(3);
    system("cls");
    return a;
}
play * insere_play(play *v, int *n, play novo) {
  v = (play*) realloc(v, (*n + 1) * sizeof(play));
  if (v == 0) {
    printf("Ops! não estamos conseguindo inserir o aluno");
  }
  v[*n] = novo;
  (*n)++;
  return v;
}

play *remove_play(play *v, int *n, int matricula) {
  for (int i = 0; i < *n; i++) {
    if (v[i].matricula == matricula) { // 1 2 3 4 | 1 3 3 4 | 1 3 4 4 | 1 3 4
      for(int j = i; j < *n - 1; j++) {
        v[j] = v[j+1];
      }
      v = (play*) realloc(v, (*n - 1) * sizeof(play));
      if (v == 0) {
        printf("Ops! não foi possivel remover alunos");
        return 0;
      }
      (*n)--;
      break;
    }
  }
  return v;
}
//______________________________________
void lista_play(play *v, int *n) {
  printf("\nSegue a lista de alunos cadastrados por ordem de cadastro: \n");
  for (int i = 0; i < *n; i++) {
    printf("\n%s\n%d\n%d\n%.1f\n%.2f\n%s\n", v[i].nome, v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);
  }
}
//_____________________________________________
int main() {
  int i, n = 0;
  play *v = 0;
  int mat = 0;
  char oper = 0;
  do{
  	printf("===MENU=== \n");
    printf("Escolha:\nI... Cadastrar Aluno\nR... Remove Aluno\nL... Listar alunos \n");
    scanf(" %c", & oper);
    system("cls");
    switch (oper) {
    case 'I':
      ;
      play novo = cadastra_play();
      v = insere_play(v, &n, novo);
      break;
    case 'R':
      scanf("%d", &mat);
      v = remove_play(v, &n, mat);
      break;
    case 'L':
      lista_play(v, &n);
    case 'S':
        system("exit");
        break;
    default:
      printf("opcao invalida");
      break;
    }
    } while(oper != 'S');

  //for (i = 0; i < n; i++)
  //printf("%s\n%d\n%d\n%.1f\n%.2f%s", v[i].nome,v[i].matricula, v[i].idade, v[i].peso, v[i].altura, v[i].posicao);   

  free(v);

  return 0;
}

 

  • Curtir 1
Postado
23 minutos atrás, Talyson Maia disse:

Lá no cadastro e no remover o menu não aparece, somente na parte de listar alunos. Sabe o porquê?

porque o menu tá dentro do seu loop do-while dentro do main e não está dentro dos metodos cadastro e remover.

moço, você colocou system exit de novo dentro do seu switch-case?
porque você acha que tem que colocar isso ai? você sabe como funciona isso?
sabe que se colocar isso ai, o seu programa sai sem ler o free(v)?

dentro do case s, você pode deixar apenas um break que vai funcionar...

ja pensou que pode colocar o menu em um metodo e chamar ele quando quiser?

 

Postado

Talyson, eu vou te passar um exemplo pra você testar ai e ver o que acontece.
O equivalente pode ser feito com qualquer outro metodo ou função que esjeta aprendendo a usar. É sempre bom fazer isso antes de querer colocar nos seus codigos, pra ter certeza de que sabe o que tá acontecendo.

A dica que dou é que tudo o que se abre, deve ser fechado, tudo o que é ligado, deve ser desligado, toda flag levantada, deve ser abaixada, se alocar espaço na memoria, deve livrar esse espaço novamente e assim vai. Quero dizer que tudo o que faz, deve ser desfeito, para manter o estado da sua maquina sempre constante, como se nem tivesse executado nenhum programa. isso é importante porque, por exemplo, as vezes você faz algo que pode impactar outros programas. A gente só deixa coisas ligadas quando sabemos muito bem que estamos fazendo isso. Isso vai depender do contexto em que tiver trabalhando. Algo que se aprende com o tempo. Eu vou indo porque apareceram outros problemas pra resolver. Espero que tenha ajudado. Desejo sucesso à você.

 


#include <stdio.h>
#include <stdlib.h>
int main() 
{

	// system("exit") não existe em c. A verdade, o que isso faz é mandar 
	// o comando para shell command para fehcar o console.
	// Não use system("exit") pra fechar o console. 
	// Exemplos de como usar chamadas de shell command estão por ultimo logo abaixo.

	// Leia esses posts que pode ajudar
	// https://docs.microsoft.com/pt-br/cpp/cpp/program-termination?view=msvc-160
	// https://stackoverflow.com/questions/8807448/cant-add-systemexit-in-c

	// descomente os 3 coments abaixo um de cada vez pra ver o que acontece
	printf("linha 1: vai funcionar!\n");
	//return 0;
	printf("linha 2: vai funcionar!\n");
	//exit(1);
	printf("linha 3: verificar se vai funcionar!\n");
	// system("exit"); 
	system("ls"); // pra quem usa linux
	system("dir"); // pra quem usa dos (Windows)
	printf("linha 4: verificar se vai funcionar!\n");
	return 0;
}

 

Postado

 

@Talyson Maia Seu programa ainda tem muitos dos mesmos erros de antes, e a essa altura já deve saber que eu tinha razão quando eu disse que era melhor escrever em torno dos dados e fazer o simples, ainda mais considerando o exemplo que te mostrei: é o programa quase pronto e tem a saída de vários testes.

 

E seu programa ainda não funciona.

 

Entendo que quer manter o modo como está fazendo a todo custo, mesmo eu tendo explicado alguns dos erros

 
Porque eu continuo escrevendo então?

Esse é um forum acessado por estudantes e iniciantes e seu exercício é bem comum e assim acho bem útil usar como exemplo para outros usuários. Os erros são também bem comuns, mas acrescenta umas coisas a serem sempre evitadas e então eu acho que vale a pena mostrar a diferença e o porque das coisas. Pode ajudar  a outros.

 

Quase todos esses exercícios para iniciantes envolvem algum tipo de container, um cadastro de alunos, uma lista de compras, uma playlist, o inevitável exercício de saques e depósitos :)

 

Eu não sei não como ensinam a programar sem falar de composição dos dados. Imagine se tivesse que mudar seu programa para acessar não um time, mas 4 times. Como ia fazer com esse folclóricos ponteiros soltos por toda parte?

 

A simples primeira constatação é que deve escrever em torno dos dados e agrupar seus players em um time. 

 

Isso é o que você usa:

 

    typedef struct
    {
        char  nome[20];
        int   matricula;
        int   idade;
        float peso;
        float altura;
        char  posicao[100];
        int   operacao;
    }     play;

    play *v    = 0;
    int n = 0;

 

play não é um bom nome. play é a palavra para jogada e não para jogador. Devia usar Player. E há uma convenção comum em C de usar a primeira letra em maiúscula em estruturas. Use. Assim ao ver uma variável assim sabe que ela é uma estrutura.

 

Do modo como escreveu seria um inferno tratar mais de um time. E mesmo tratar um só time já é chato como você está vendo. Todos os seu dados estão escondidos atrás dessa letrinha v, e se supões que seja um vetor de Player.

 

E a singela variável n é o total de play, e eles estão em v[0] até v[n-1]

 

Difícil de ler.

 

Compare
 


    typedef struct
    {
        char  nome[20];
        int   matricula;
        int   idade;
        float peso;
        float altura;
        char  posicao[100];
        int   operacao;

    }   Player;


    typedef struct
    {
        int     n;
        Player* pl;

    }   Team;

    Team alfa;
    Team UFRJ[20];

 

Um Team é um time e tem Team.n jogadores. alfa é um time, mas UFRJ é um vetor de 20 times e para o programa não faz diferença. DENTRO de cada time estão os jogadores. É o simples e é o que o mundo inteiro usa. 

 

Isso está errado

 

 

image.png.9813cbde03366f25bd1517da45159f5b.pngNa opção 'S' do case você escreveu system("exit") e não faz sentido.

 

Apenas use exit(). Não tem sentido chamar system() para passar essa linha para o sistema. Em C se usaria simplesmente exit().

 

Não deve usar system(). Nunca. É proibida em toda parte, empresas e escolas.

 

Mas não é só isso que está errado: ao chamar exit() vai encerrar seu programa e nunca vai vai sair do loop. 

 

Isso quer dizer que nunca vai rodar aquele comando free() que tem depois do loop :( 

 

Mais ainda, quer dizer que nuca vai passar por aquele teste 
 

    while ( oper != 'S' )

 

já que se a opção for 'S' o programa já terá terminado no meio do loop. Se está escrevendo isso para ter uma nota vai perder uma boa parte dela. 

 

Sobre seu programa

 

        printf("===MENU=== \n");
        printf(
            "Escolha:\nI... Cadastrar Aluno\nR... Remove Aluno\nL... "
            "Listar alunos \n");
        scanf(" %c", &oper);
        system("cls");

 

Está muito difícil de ler isso. E entenda que

  • um printf() de várias linhas é bem mais esperto que vários printf de uma linha. São chamadas de função e isso demora.
  • teste sempre o retorno de scanf()
  • em geral você limpa a tela ANTES e não depois de escrever o menu. Como fez não vai saber o que tinha na tela antes  tal menu pode ser escrito depois de qualquer coisa que já tenha na tela. Nunca é o que se quer.
  • Use uma função para o menu. É mais simples de controlar e deixa o código mais legível.

 

Compare:

 

    char  oper = 0;
    while ( (oper = menu()) != 'S')
    {
        switch (oper)
        {
        case 'I':;
            play novo = cadastra_play();
            v         = insere_play(v, &n, novo);
            break;
        case 'R':
            scanf("%d", &mat);
            v = remove_play(v, &n, mat);
            break;
        case 'L':
            lista_play(v, &n);
            break;
        };  // switch()
    };  // while()

 

Não é mais simples?

 

E menu() ?

 

Compare com o modo como escreveu 
 

image.thumb.png.a92e2fdaae35f1fb25d854b6ffa56075.png

 

Como escrito à direita é muito mais fácil de saber como vai sair na tela e de mudar se preciso.

Note que seu menu não tem a opção 'S' ;) 

 

Uma menu() simples:
 

char menu()
{
    char oper = 0;
    system("cls");
    printf(
        "\
===MENU=== \n\
Escolha:\n\
I... Cadastrar Aluno\n\
R... Remove Aluno\n\
L... Listar alunos\n\
S... Sair\n\
     Sua opcao: ");
    if (scanf(" %c", &oper) != 1) return 'X';  // não leu nada
    switch (oper)
    {
        case 'i':
        case 'I':
            return 'I';
        case 'R':
        case 'r':
            return 'R';
        case 'L':
        case 'l':
            return 'L';
        case 'S':
        case 's':
            return 'S';
        default:
            return 'X';
    };           // switch()
    return 'X';  // para contentar o compilador
};

 

Nesse caso é mais simples de ler e melhor para usar. E trata as minúsculas. E retorna um 'X' se não ler nada.

 

E em main() fica mais limpo, por exemplo com seu código:

 

int main()
{
    int   n    = 0;
    play *v    = 0;
    int   mat  = 0;
    char  oper = 0;
    while ((oper = menu()) != 'S')
    {
        switch (oper)
        {
        case 'I':;
            play novo = cadastra_play();
            v         = insere_play(v, &n, novo);
            break;
        case 'R':
            scanf("%d", &mat);
            v = remove_play(v, &n, mat);
            break;
        case 'L':
            lista_play(v, &n);
            break;
        };  // switch()
    };      // while()
    free(v);
    return 0;
}

 

É o comum.

 

lista_play()

 

    void lista_play(play *v, int *n)

 

Essa função não vai mudar o valor de n. Não há razão para passar o endereço. Escreva
 

    void lista_play(Player *v, int n)

 

Isso garante que um bug na função alterando o valor de n não vai se propagar pelo programa todo. E na verdade seria melhor declarar const int n como uma defesa a mais. Não deixe pontas soltas.

 

insere_play()

 

A lógica do que está fazendo é usar um críptico v para ter todos os dados do programa, e um minimalista n para dizer quantos tem lá dentro.

 

E quando vai inserir chama realloc() e aumenta de um o tamanho do vetor. Eis o código
 

Player *insere_play(Player *v, int *n, Player novo)
{
    v = (Player *)realloc(v, (*n + 1) * sizeof(Player));
    if (v == 0)
    {
        printf("Ops! não estamos conseguindo inserir o aluno");
    }
    v[*n] = novo;
    (*n)++;
    return v;
}

 

Como não criou uma estrutura para o time tem que repassar o ponteiro para o contador n. E o endereço de v, que já é um ponteiro... Complicado sem razão. E vai retornar v de novo.

 

Está ruim de ler, mas está também errado.

 

Se realloc() der erro o endereço de v vai estar comprometido. De nada adianta apenas escrever aquela mensagem já que vai retornar 0.

 

Na verdade nem vai retornar: seu programa vai cancelar na linha seguinte ao printf():
 

    v[*n] = novo;  // vai morrer aqui

 

porque v será 0, o popular NULL. nunca vai retornar.

 

O recomendado em C é escrever com cuidado:
 

Player *insere_play(Player *v, int *n, Player novo)
{
    Player* nova_area = (Player*)
        realloc(v, (*n + 1)*sizeof(Player) ); // aumentou 1
    if (nova_area == NULL)
    {
        printf("Ops! não estamos conseguindo inserir o aluno");
        return v; // preservado em caso de erro
    }
    nova_area[*n] = novo; // poe o novo no fim
    (*n) += 1; // conta o novo
    return nova_area; // retorna o novo bloco
}

 

Mas nunca se escreve assim.

 

Porque? realloc() não garante que vai estender o bloco lá onde ele está. Muita vezes o bloco todo é realocado para outro lugar. Pode ser sempre realocado. Não há garantia exceto a de que não há garantia. Isso quer dizer que a cada inserção todo o bloco é copiado. 140 bytes para cada jogador.

 

Por isso não se usa essa técnica. Não é esperto. 

 

Em geral se aloca memória em blocos. Por exemplo 20 jogadores por vez. E aí quando acaba aloca mais 20 ou o dobro do que tinha, para minimizar as chamadas e as possíveis operações de cópia. Ou se criam páginas de jogadores para não ter que mover nunca. Acabou, cria outra. O sistema faz isso.

 

Para alocar um a um se usa lista encadeada.

 

 

 

 

 

 

 

 

 

remove_play()

 

Também está errado:
 

Player *remove_play(Player *v, int *n, int matricula)
{
    for (int i = 0; i < *n; i++)
    {
        if (v[i].matricula == matricula)
        {  // 1 2 3 4 | 1 3 3 4 | 1 3 4 4 | 1 3 4
            for (int j = i; j < *n - 1; j++) { v[j] = v[j + 1];
        }
        v = (Player *)realloc(v, (*n - 1) * sizeof(Player));
        if (v == 0)
        {
            printf("Ops! não foi possivel remover alunos");
            return 0;
        }
        (*n)--;
        break;
        }
    }
    return v;
}

 

Se não tiver ninguém com a tal matrícula vai realocar e apagar o último infeliz jogador.

 

Eu te mostrei o código e um teste que pode usar nesse caso...

 

E tem o mesmo erro de realloc() que mostrei antes para a função que insere. Sempre se usa realloc() em um ponteiro temporário local. Ou nem se testa o retorno afinal.

  • Curtir 1
  • Obrigado 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

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!