Ir ao conteúdo

Posts recomendados

Postado

Pessoal, beleza ?

 

Tenho uma dúvida e gostaria de saber se podem ajudar. Não sei se existe essa possibilidade mas seria muito interessante se funcionasse.

Será possível utilizar uma variável para apontar qual parâmetro manipular em um ponteiro de uma struct ?

 

Veja abaixo:

 

typedef struct{
int atributo1;
float atributo2;
}estrutura;

//prototipo da funcao
void funcao(estrutura *pexemplo);

int main(){

	estrutura exemplo;
	estrutura *pexemplo;

funcao(pexemplo);

}

void funcao(estrutura *pexemplo){
	char variavel[] = "atributo1";

	pexemplo->variavel = 100; // algo do tipo    

}
pexemplo->&variavel = 100; // tentei nao funciona

 

  • Curtir 1
Postado

@KXSY  agradeço pela resposta, mas não é bem isso. Minha intenção é alterar um atributo da struct a partir de uma variável. 

pexemplo->variável // onde essa variavel poderia assumir valores distintos ( pra não ficar hard coded)  - qualquer parâmetro da stuct

 

  • Curtir 1
Postado
8 horas atrás, guhbrj disse:
8 horas atrás, guhbrj disse:

Minha intenção é alterar um atributo da struct a partir de uma variável

 

8 horas atrás, guhbrj disse:

utilizar uma variável para apontar qual parâmetro manipular em um ponteiro de uma struct

 

Esta referência a variável, ponteiro, parâmetro e atributo está um pouco confusa. De todo modo, entenda que em algum ponto do programa vai ter que definir qual variável vai alterar afinal, e hard-code it,  de certa forma.

 

De modo geral em C isso se faz usando a lógica do problema para identificar qual campo vai alterar, e um (void*) para fornecer o endereço da variável a alterar dentro da struct.

É a lógica usada por exemplo na função qsort(), declarada assim

void qsort (
    void* base, size_t num, size_t size,
    int (*compar)(const void*,const void*)
);

onde você declara a função de comparação como (void*) e isso permite comparar qualquer struct por qualquer critério, tornando o qsort() --- QuickSort --- genérico e capaz de classificar qualquer coisa.
 

Ou funções de string.h como memcpy() declarada assim

void * memcpy ( void * destination, const void * source, size_t num );

onde o uso de (void*) deixa tudo genérico.
 

Talvez você pudesse postar o programa inteiro, ou uma parte compilável, de modo a ajudar o pessoal a ajudar você.

 

Usando essa ideia em seu programa, e o valor 0 para o alterar o int e 1 para alterar o float, e mudando função para isso
 

    void funcao(estrutura* pexemplo, void*, const char);

 

Esse (seu) código funcionaria

int main()
{
    estrutura exemplo   = { 0,0 };
    estrutura* pexemplo = &exemplo;
    void* p;
    int i = 1001;
    float f = (float)12.345678;

    printf("antes: atributo1 = %d, atributo 2 = %f\n", exemplo.atributo1, exemplo.atributo2);

    p = (void*)&i;
    funcao(pexemplo, p, 0);
    p = (void*)&f;
    funcao(pexemplo, p, 1);

    printf("depois: atributo1 = %d, atributo 2 = %f\n", exemplo.atributo1, exemplo.atributo2);
}

E mostraria

antes: atributo1 = 0, atributo 2 = 0.000000
depois: atributo1 = 1001, atributo 2 = 12.345678

Uma implementação para funcao():

void funcao(estrutura* e,  void* p, const char qual)
{
	if (qual == 0)
	    e->atributo1 = *((int*)p);
	else
		e->atributo2 = *((float*)p);
	return;
};	// funcao()

Uma tentativa de recriar (seu) programa de teste inteiro:

#include "stdio.h"

typedef struct
{
    int      atributo1;
    float    atributo2;
}    estrutura;

//prototipo da funcao
void funcao(estrutura* pexemplo, void*, const char);

int main()
{
    estrutura exemplo = { 0,0 };
    estrutura* pexemplo = &exemplo;
    void* p;
    int i = 1001;
    float f = (float)12.345678;

    printf("atributo1 = %d, atributo 2 = %f\n", exemplo.atributo1, exemplo.atributo2);

    p = (void*)&i; // atributo1 passa a ser 1001
    funcao(pexemplo, p, 0);
    p = (void*)&f; // atributo2 pasa a ser 12.345678
    funcao(pexemplo, p, 1);

    printf("atributo1 = %d, atributo 2 = %f\n", exemplo.atributo1, exemplo.atributo2);
}

void funcao(estrutura* e,  void* p, const char qual)
{
    if (qual == 0)
         e->atributo1 = *((int*)p);
     else
         e->atributo2 = *((float*)p);
     return;
};    // funcao()

 

Um exemplo mais completo:

 

usando essa struct

struct exemplo
{
    int       i_parametro;
    double    d_parametro;
    char*     s_parametro;
    int       (*f_parametro_i)(int);
    void      (*f_parametro_v)(int, int);
};

você teria também uma string e duas funções, mas poderia continuar usando a mesma ideia


Usando essas constantes para o valor de índice

#define        _INTEGER_        0
#define        _DOUBLE_         1
#define        _STRING_         2
#define        _FUNCTION_INT_   3
#define        _FUNCTION_VOID_  4

 

fica mais fácil de ler o código.
O trecho abaixo mudaria os 5 valores usando o único ponteiro p, os valores e essa funcão
void carrega_struct(exemplo* ps, void* p, const char qual);

    int        i_val = 2020;
    p = (void*)&i_val;
    carrega_struct(ps, p, _INTEGER_);

    // double
    double        d_val = 2020.123456;
    p = (void*)&d_val;
    carrega_struct(ps, p, _DOUBLE_);

    // a string
    char* string = malloc( sizeof(char) * strlen(teste) + 1);
    memcpy( string, teste, strlen(teste)+1);
    p = (void*) string;
    carrega_struct(ps, p, _STRING_);

    // a funcao que retorna int a partir de um int
    p = (void*)teste1;
    carrega_struct(ps, p, _FUNCTION_INT_);

    // a funcao void que recebe dois int
    p = (void*)teste11;
    carrega_struct(ps, p, _FUNCTION_VOID_);

E a função pode ser escrita assim, apenas para você ver como tratar outros tipos de membros na struct

void        carrega_struct(Exemplo* E, void* p, const char indice)
{    // usa o indice para carregar a struct a partir do pointer p
    switch (indice)
    {
        case _INTEGER_:
            E->i_parametro = *((int*)p);
            break;
        case _DOUBLE_:
            E->d_parametro = *((double*)p);
            break;
        case _STRING_:
            E->s_parametro = (char*)p;
            break;
        case _FUNCTION_INT_:
            E->f_parametro_i = p;
            break;
        case _FUNCTION_VOID_:
            E->f_parametro_v = p;
            break;
        default:
            printf("indice invalido para a struct: ignorado\n");
            break;
    };    // switch()
    return;

Um programa de teste para essa struct expandida :D

#include "malloc.h"
#include "memory.h"
#include "stdio.h"
#include "string.h"

#define		_INTEGER_		0
#define		_DOUBLE_		1
#define		_STRING_		2
#define		_FUNCTION_INT_	3
#define		_FUNCTION_VOID_	4

struct exemplo
{
	int		i_parametro;
	double	d_parametro;
	char*	s_parametro;
	int		(*f_parametro_i)(int);
	void	(*f_parametro_v)(int, int);
};

typedef struct exemplo	Exemplo;

void		carrega_struct(Exemplo*, void*, const char);
void		mostra_struct(Exemplo*);

int			teste1(int);
int	    	teste2(int);
void		teste11(int,int);
void		teste22(int,int);



int main(int argc, char** argv)
{
	const char* teste = "Uma string foi carregada a partir do parametro";
	void* p;
	Exemplo		a_struct;
	Exemplo* ps = &a_struct;
	// coloca valores conhecidos na struct
	a_struct.i_parametro = 1;
	a_struct.d_parametro = 2.3;
	a_struct.s_parametro = 0;
	a_struct.f_parametro_i = NULL;
	a_struct.f_parametro_v = NULL;
	printf("\nValores iniciais na struct\n");
	mostra_struct( ps );
	// agora usa o indice para alterar a struct a partir do ponteiro
	// integer
	int		i_val = 2020;
	p = (void*)&i_val;
	carrega_struct(ps, p, _INTEGER_);

	// double
	double		d_val = 2020.123456;
	p = (void*)&d_val;
	carrega_struct(ps, p, _DOUBLE_);

	// a string
	char* string = malloc( sizeof(char) * strlen(teste) + 1);
	memcpy( string, teste, strlen(teste)+1);
	p = (void*) string;
	carrega_struct(ps, p, _STRING_);

	// a funcao que retorna int a partir de um int
	p = (void*)teste1;
	carrega_struct(ps, p, _FUNCTION_INT_);

	// a funcao void que recebe dois int
	p = (void*)teste11;
	carrega_struct(ps, p, _FUNCTION_VOID_);

	printf("\nDepois de alterar os valores usando o ponteiro e os indices respectivos\n");
	mostra_struct( ps );

	// troca as duas funcoes
	printf("\nDepois de trocar os ponteiros das duas funcoes\n");
	p = (void*)teste2;
	carrega_struct(ps, p, _FUNCTION_INT_);
	p = (void*)teste22;
	carrega_struct(ps, p, _FUNCTION_VOID_);
	mostra_struct(ps);

	return 0;
}	// main()


void		carrega_struct(Exemplo* E, void* p, const char indice)
{	// usa o indice para carregar a struct a partir do pointer p
	switch (indice)
	{
		case _INTEGER_:
			E->i_parametro = *((int*)p);
			break;
		case _DOUBLE_:
			E->d_parametro = *((double*)p);
			break;
		case _STRING_:
			E->s_parametro = (char*)p;
			break;
		case _FUNCTION_INT_:
			E->f_parametro_i = p;
			break;
		case _FUNCTION_VOID_:
			E->f_parametro_v = p;
			break;
		default:
			printf("indice invalido para a struct: ignorado\n");
			break;
	};	// switch()
	return;
}


void		mostra_struct(Exemplo* E)
{
	printf("\n--------------------\n");
	printf("int = %d\n", E->i_parametro);
	printf("double = %f\n", E->d_parametro);
	printf("string = \"%s\"\n", E->s_parametro);
	if (E->f_parametro_i != NULL)
	{
		printf("Chamando a 'int funcao(int)' apontada pela struct\n");
		(*E->f_parametro_i)(1);
	}
	else
	{
		printf("inf f(int) nao esta definida\n");
	};	// if

	if (E->f_parametro_v != NULL)
	{
		printf("Chamando a funcao 'void funcao(int, int)' apontada pela struct\n");
		(*E->f_parametro_v)(2,3);
	}
	else
	{
		printf("void f(int,int) nao esta definida\n");
	};	// if
	printf("--------------------\n");
	return;
};


int		teste1(int a)
{
	printf("teste1(%d) chamada\n", a);
	return 0;
};


int		teste2(int a)
{
	printf("teste2(%d) chamada\n", a);
	return 0;
};


void	teste11(int a, int b)
{
	printf("teste11(%d,%d) chamada\n", a, b);
	return;
};


void	teste22(int a, int b)
{
	printf("teste22(%d,%d) chamada\n", a, b);
	return;
};

 

  • Curtir 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...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!