Ir ao conteúdo
  • Cadastre-se
soumma

C++ Retornando array 2d de funções

Posts recomendados

Começei a resolver um problema e acabei fazendo uma coisa que nunca tinha feito antes em c++ que eh passar arrays 2d de char por funções. Vi que não é tão simples qto em Java e acabei pesquisando sobre e vi que uma das maneiras seria voce criar um array de ponteiros que apontasse para cada um para um array de char e ficou assim:

char** createTable(int m, int n){
	char** arr;
	arr = new char*[m];
	for (int i = 0; i < m; i++) {
		arr[i] = new char[n];
		for (int j = 0; j < n; j++) {
			arr[m][n] = '0';
		}
	}
		return arr;
}

int main() {
	int m, n;
    cin >> m >> n;
	char** arr = createTable(m, n);
  
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			cout << arr[i][j] << " ";
		}
		cout << endl;
	}
  
	return 0;
}

O lance é que a tarefa buga quando passo os input de m e n e então encerra. Eu procurei em varios topicos e a maioria das soluções é essa que fiz igualzinho ou usar vector. Alguem pra me dar uma luz? Se conseguir me mostrar como fazer isso com vector tambem seria da hora, valeu!!!

  • Amei 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@soumma    testei seu código aqui no codeblocs e está funcionando bem ,  teste esse aqui novamenye :

#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
char** createTable(int m, int n){
    char** arr;
    arr = new char*[m];
    for (int i = 0; i < m; i++) {
        arr[i] = new char[n];
        for (int j = 0; j < n; j++) {
            arr[i][j] = '0';
        }
    }
    return arr;
}
int main(){
    int m, n;
    cin >> m >> n;
    char** arr = createTable(m, n);

    for (int i = 0; i < m; i++) {
        cout<<setw(3)<<i+1<<" -> ";
        for (int j = 0; j < n; j++) {
            cout<<arr[i][j]<<" ";
        }
        cout << endl;
    }
    return 0;
}

 

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

O erro está aqui:

for (int i = 0; i < m; i++) {
		arr[i] = new char[n];
		for (int j = 0; j < n; j++) {
			//arr[m][n] = '0'; erro
			arr[i][j] = 0;
		}
	}

Edti: Não esquecer de liberar a memória (chamar delete).

  • Curtir 2

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

@Flávio Pedroza Mano nem acredito que usei os indices errados sem querer, obrigado.

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Porque em java seria mais simples? Tem um exemplo? Porque não usou strings em C++?
Em java não poderia alocar nada, e então não precisaria liberar nada. Mas não fez isso em seu programa então não faria muita diferença, eu acho. Foi a diferença que me ocorreu. 

 

Não sei se consegui entender ao certo o que quer fazer mas parece ser um tema útil para outros também, então escrevi um programa de exemplo

 

"retornar um array 2D de funções" --- o que está no título ---


Seria como retornar uma matriz MxN de endereços de funções. Não é o que seu programa faz e acho que não é o que pretende. Mas vou mostrar esse caso.

 

"passar arrays 2D de char por funções"

 

Pelo seu código

char** createTable(int m, int n)
{
    int total = m*n;
    arr = new char* [m];
    for (int i = 0; i < m; i++) {
        arr[i] = new char[n];
        for (int j = 0; j < n; j++) {
            arr[m][n] = '0';
        }
    }
    return arr;
}

parece pretender retornar um array de strings, como o argv do C/C++, com uma string para cada linha.


Ou seria o caso de retornar uma matriz (MxN) de char com '0'?
 

Considere M = 6 e N = 4 nesse exemplo adiante.
 

1: Como sua rotina parece fazer:


O resultado aparentemente esperado para createTable() seria então 

000
000
000
000
000
000

onde arr[0] até arr[5] seriam strings e temos 4 bytes para cada uma. Como tem que ter um null para terminar a string restam 3 para colocar o '0' cujo valor é 48 na tabela, e o 0 vem depois.
seu programa cancela por isso (ou pela falta disso: o null ao final)..

 

Assim funcionaria:

char** createTable(int m, int n)
{
    char** arr;

    arr = new char* [m];
    for (int i = 0; i < m; i++)
    {
        arr[i] = new char[n];
        for (int j = 0; j < n - 1; j++)
            arr[i][j] = '0';
        arr[i][n - 1] = 0;
    };
    return arr;
}


2: Uma matriz de char MxN


Esse é o caso mais comum. O resutado esperado seria uma coisa assim, usando '0' como fez para preencher:

0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

Assim funcionaria:

char* createTableXY(const int m, const int n)
{
    char* arr = new char[m*n];
    memset(arr,'0', m*n);
    return arr;
}

E poderia chamar assim, e mostra a matriz a seguir:

    char* coisa = createTableXY(m,n);
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cout << *(coisa + i*n + j) << " ";
        }; // for (j)
        cout << endl;
    };    // for(i)
    // game over: apaga os caras
    delete coisa;

O que importa aqui é isso:

*(coisa + i*n + j); // para acessar o elemento (i,j) da matriz

(Dias atrás teve uma discussão aqui nesse forum de como acessar um elemento para uma matriz com qualquer número de índices, e tem lá um programa de teste e referências.)


3: Um array 2D de funções


Esse é mais raro e mais enjoado. É absolutamente essencial em C, C++, java e o diabo, mas em geral é transparente para quem usa. No caso de java e C++ é a maneira de se implementar funções virtuais, classes abstratas, aquelas coisas. É criada uma tabela de funções, chamada VFT --- virtual function table --- que define qual função vai ser chamada para uma certa classe virtual. Postei um exemplo disso aqui um dia desses.

 

Vou dar um exemplo aqui pra ficar mais completo, ainda que poucos tenham paciência de ler. Respostas curtas são tão mais legais!

 

Em C/C++

Isso declara pFteste como o endereço de uma função que retorna int e recebe dois int como argumentos

    int (*pFteste)(int, int);

Então você pode escrever

typedef int (*pF)(int, int);

E

pF** cria_vetor_2D(const int, const int);

E esse poderia ser o protótipo de uma função que retornaria um vetor 2D de ponteiros para função.


Você chamaria assim, no nosso exemplo:

    pF** teste_v2D = cria_vetor_2D(M,N);

Para não complicar, considere essa função

int modelo(int a, int b)
{
    cout << "funcao(" << a << "," << b << ")" << endl;
    return a * b;
};    // modelo()

Ela recebe dois int mostra os valores e retorna o produto deles. E serve para o nosso pF. Claro que normalmente se usa (void*) para as funções e depois converte para o que for preciso, como o qsort() no C por exemplo.

 

Veja uma implementação de cria_vetor_2D() que preenche a matriz de funções com o endereço dessa aí e retorna o endereço da tal matriz

// cria vetor 2D de funcoes
pF** cria_vetor_2D(const int x, const int y)
{
    pF** v2D = new pF* [x];
    for (int i = 0; i < x; i++)
    {
        v2D[i] = new pF[y];
        for (int j = 0; j < y; j++)
            v2D[i][j] = modelo;
    };    // for (i)
    pF a = modelo;
    (*a)(1, 2);
    return v2D;
}; // cria_vetor_2D()

 

E Como chama um trem desses?


Simples. No exemplo MxN que temos essas 3 linhas criam a matriz e chamam a primeira e a última função na matriz, só para testar:

 

    pF** teste_v2D = cria_vetor_2D(M,N);
    (*teste_v2D[0,0])(3,8);
    (*teste_v2D[M - 1, N - 1])(M - 1, N - 1);


Como apagar essas coisas?

Atente para o fato de que ao alocar um array em C++ depois PRECISA usar colchetes no delete. Então para apagar a matriz por exemplo precisa escrever assim:

    // game over: apaga os caras
    for (int i = 0; i < M; i++)
        delete[] arr[i];
    delete arr;

Eis o resultado do programa exemplo, que usa as 3 opções

Testando para M = 6 e N = 4

1: uma string por linha

linha: 0 [000]
linha: 1 [000]
linha: 2 [000]
linha: 3 [000]
linha: 4 [000]
linha: 5 [000]

2: matriz MxN de caracteres

0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

3: array 2D de funcoes

funcao(3,8)
retornou 24
funcao(5,3)
retornou 15

E o programa

#define _CRT_SECURE_NO_WARNINGS

// https://www.clubedohardware.com.br/forums/topic/
// 1427656-retornando-array-2d-de-fun%C3%A7%C3%B5es/
// ?tab=comments#comment-7699344

#include <iostream>
#include <string.h>

typedef int (*pF)(int, int);

char**     createTable(int, int n);
char*      createTableXY(const int, const int);
pF**       cria_vetor_2D(const int, const int);
int        modelo(int, int);


using namespace std;


int main(int argc, char** argv)
{
    int M = 6;
    int N = 4;
    cout << "Testando para M = " << M <<
        " e N = " << N << endl;
    cout << "\n1: uma string por linha\n\n";
    char** arr = createTable(M, N);
    for (int i = 0; i < M; i++)
    {
        cout <<
            "linha: " << i <<
            " [" << arr[i] << "]" << endl;
    }
    // game over: apaga os caras
    for (int i = 0; i < M; i++)
        delete[] arr[i];
    delete arr;

    //
    cout << "\n2: matriz MxN de caracteres\n\n";
    char* coisa = createTableXY(M, N);
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
            cout << *(coisa + i * N + j) << " ";
        }; // for (j)
        cout << endl;
    };    // for(i)
    // game over: apaga os caras
    delete coisa;

    cout << "\n3: array 2D de funcoes\n\n";
    pF** teste_v2D = cria_vetor_2D(M, N);
    int r = (*teste_v2D[0, 0])(3, 8);
    cout << "retornou " << r << endl;
    r = (*teste_v2D[M - 1, N - 1])(M - 1, N - 1);
    cout << "retornou " << r << endl;
    for (int i = 0; i < M; i++)
        delete[] teste_v2D[i];
    delete teste_v2D;
    return 0;
};    // main()


char** createTable(int m, int n)
{
    char** arr;

    arr = new char* [m];
    for (int i = 0; i < m; i++)
    {
        arr[i] = new char[n];
        for (int j = 0; j < n - 1; j++)
            arr[i][j] = '0';
        arr[i][n - 1] = 0;
    };
    return arr;
}; //createTable()


char* createTableXY(const int m, const int n)
{
    char* arr = new char[m * n];
    memset(arr, '0', m * n);
    return arr;
};    // createTableXY()


pF** cria_vetor_2D(const int x, const int y)
{
    int (*pFteste)(int, int);
    pF** v2D = new pF * [x];
    for (int i = 0; i < x; i++)
    {
        v2D[i] = new pF[y];
        for (int j = 0; j < y; j++)
        {
            v2D[i][j] = modelo;
        }; // for (j)
    };    // for (i)
    return v2D;
};  // cria_vetor_2D()


int modelo(int a, int b)
{
    cout << "funcao(" << a << "," << b << ")" << endl;
    return a * b;
};    // modelo()

 

 

 

 

 

  • Curtir 2

Compartilhar este post


Link para o post
Compartilhar em outros sites

@soumma Boa Tarde!

 

Exatamente, matrizes (em C) são objetos e seu acesso entre escopos é por meio de um ponteiro (ou referência). O método adotado (alocar ponteiro para gerar linhas) é muito  justo quando  é de bytes que variam por linha.

 

Por exemplo: Dicionários. 

Trabalhando com matrizes de largura n-contante use apenas 1 e não m-ponteiros para indexa as linhas da matriz.

char (* array)[N] = // Alocar memória Linhas * N...

 

Bons Estudos!

 

 

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Estive procurando um exemplo de como endereçar uma área para acessar com 1 índice ou 2 ou talvez mais e não encontrei quase nada, exceto por umas notas no conhecido C FAQ em http://c-faq.com/about.html

 

Então escrevi um exemplo e vou postar aqui. Talvez ajude alguém em algo que eu acho um inferno: como acessar algo assim.

 

Não há razão para uma classe aqui: basta uma struct e assim pode ser usado em C também o mesmo código, ou quase.

 

A estrutura é uma bobagem, só para exemplo, e é algo como uma variante, ou tagged union como se lê às vezes:

struct multiD
{
	int len;
	union
	{
		int(*x1D)[60];
		int(*x2D)[4][15];
		int(*x3D)[3][4][5];
		int(*x4D)[2][3][2][5];
		int(*x5D)[1][2][2][3][5];
	};
};

É só para mostrar 

  • como declarar ponteiros para vetores
  • como usar uma union anônima --- sem nome --- para acessar a mesma área na memória com variáveis alternativas, o tal registro variante

O programa é bem linear:

  • aloca o vetor com 60 posições, int, e numera todas de 00 a 59
  • acessa o vetor como uma matriz de 1 a 5 dimensões e mostra como acessar os valores usando os operadores tradicionais []. Usando ponteiros é mais simples e tem um programa aqui no forum que mostra isso, de umas semanas atrás. Pesquise por Tanenbaun + índices + arfneto e deve aparecer. O objetivo aqui era usar os colchetes.
  • mostra todos os valores nas possíveis dimensões
  • mostra o último valor em cada matriz para ver que é o mesmo 59

Veja o final da saída do programa

O ultimo elemento, visto com 1 a 5 indices, deve ser o mesmo:

1D v[59] = 59
2D v[3][14] = 59
3D v[2][3][4] = 59
4D v[1][2][1][4] = 59
5D v[0][1][1][2][4] = 59

ARFNETO 2020

O programa é simples, e gira em torno da struct e dessa função

void mostra(multiD* matriz, int planos){};

que recebe uma struct e acessa com os índices certos para o número de planos passado...
 

Veja o caso para uma dimensão, usando ponteiros porque eu esqueci que ia usar só índices :D e agora não vou mudar mais

	case 1:
		//	int(*x1D)[60];
		for (int i = 0; i < matriz->len; i += 1)
		{
			std::cout << setw(2) << i << ": " <<
				setw(2) << *(*(matriz->x1D) + i) << " ";
			if (i % 10 == 9) cout << endl;
		};	// for
		break;

E para 3

	case 3:
		//	int (*x3D)[3][4][5];
		for (int i = 0; i < 3; i += 1)
			for (int j = 0; j < 4; j += 1)
				for (int k = 0; k < 5; k += 1)
					std::cout << "(" <<
					setw(2) << i << "," <<
					setw(2) << j << "," <<
					setw(2) << k << ") = " <<
					(*matriz->x3D)[i][j][k] << endl;
		break;

E um trecho do programa principal

	// exemplos de vetores xD
	int v1D[60];
	int v2D[4][15];
	int v3D[3][4][5];
	int v4D[2][3][2][5];
	int v5D[1][2][2][3][5];

	multiD teste;	// estrutura de teste
	teste.len = 60;
	teste.x1D = &v1D;// so testes, para mostrar o acesso
	teste.x2D = &v2D;// so testes, para mostrar o acesso
	teste.x3D = &v3D;// so testes, para mostrar o acesso
	teste.x4D = &v4D;// so testes, para mostrar o acesso
	teste.x5D = &v5D;// so testes, para mostrar o acesso
	// preenche usando o vetor v1D
	teste.x1D = &v1D;
	// for (int i = 0; i < teste.len; i += 1) *(*(teste.x1D) + i) = i; // igual
	for (int i = 0; i < teste.len; i += 1) (*teste.x1D)[i] = i;
	// mostra a mesma area de 1 a 5 dimensoes
	for (int i = 1; i <= 5; i += 1)
		mostra(&teste, i);
	// nada a liberar: so usamos valores estaticos
	// agora mostra o ultimo elemento de cada vetor
	cout << "\nO ultimo elemento, visto com 1 a 5 indices, deve ser o mesmo:\n" << endl;
	cout << "1D v[59] = " << (*teste.x1D)[59] << endl;
	cout << "2D v[3][14] = " << (*teste.x2D)[3][14] << endl;
	cout << "3D v[2][3][4] = " << (*teste.x3D)[2][3][4] << endl;
	cout << "4D v[1][2][1][4] = " << (*teste.x4D)[1][2][1][4] << endl;
	cout << "5D v[0][1][1][2][4] = " << (*teste.x5D)[0][1][1][2][4] << endl;

Se alguém precisar, o programa pode ser baixado aqui, ou lido lido aqui

 

O que importa é só como declarar e como acessar as diferentes matrizes, e o lance da variante, que é um conceito muito útil para quando você vai receber um registro que tem um certo número de formatos, dependendo muitas vezes de algum prefixo identificador

 

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Em 16/02/2020 às 12:12, soumma disse:

 

@Flávio Pedroza Mano nem acredito que usei os indices errados sem querer, obrigado.

Fiquei confuso também porque lendo não aceitei, imediatamente, o erro de execução.

 

Então acredite, pois é mais comum do que pensa; Use palavras para variáveis e letra para os índices, não sei explicar a razão mais isso minimiza confusões desse tipo.

 

Bons Estudos!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro 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 publicações 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...

Aprenda a ler resistores e capacitores

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!