Concordo, mas ele não quer que use.
Felipe
template <typename T, size_t M, size_t N>
int* opt_bin( const T(*rf)[M][N] )
{
int i, j, k;
int (*best)[M+1][N+1]
T cost[M+1][N+1];
best = (int (*)[M+1][N+1])new int[(M+1)*(N+1)];
...
return (int*)best;
}
O "cost" não precisa ser alocado. O best deve ser acessado assim:
(*best)[i][j]
Uma dúvida para os experts da lista: Porque não posso fazer assim?
best = new int[M+1][N+1]; // Não funciona!!!
Márcio Gil.
> -----Mensagem original-----
> De: ccppb...@googlegroups.com
> [mailto:ccppb...@googlegroups.com] Em nome de Felipe
> Enviada em: segunda-feira, 12 de maio de 2008 00:05
> Para: ccppbrasil
> Assunto: Problema com código
int **opt_bin( double **rf, int n )
{
...
}
e se você declarou a sua matriz como:
double matriz[n][n];
não vai poder passar esta matriz diretamente para a função. Terá que
declarar assim:
double **matriz;
matriz = new double*[n];
for (int i = 0; i < n; i++)
matriz[i] = new double[n];
...
int **best = opt_bin( matriz, n );
ou fazer assim:
double matriz[n][n]
double *rf[n];
for (int i = 0; i < n; i++)
rf[i] = matriz[i];
...
int **best = opt_bin( rf, n );
Atenciosamente,
Márcio Gil.
Porque não faz sentido? O código original recebia uma matriz quadrada que
era tratada como se fosse um vetor unidimensional justamente porque em C não
dá para passar uma matriz de tamanho desconhecido. Em seguida ele alocava o
espaço para uma nova matriz quadrada de dimensão n+1. Em C ou C++
"int[3][4]" é a especificação para um tipo "matriz inteira 3 x 4", logo o
template não me dá o tamanho do array mas a especificação das dimensões do
tipo da matriz passada.
> Ou você faz uma coisa ou outra.
Se eu trabalhar sem alocação dinâmica não vou poder retornar uma matriz
maior do que a recebida. Se trabalhar só com ponteiro para inteiro e
alocação dinâmica vou ter que continuar trabalhando com a fórmula
(i*(n+1)+j). A minha sugestão era para ele deixar de utilizar
"best[i*(n+1)+j]" e passar a utilizar "(*best)[i][j]".
> Para passar um array e descobrir o tamanho com templates ele tem que
> ser alocado na pilha e você tem que usar referencia.
O que a função está recebendo é um ponteiro para matriz, não vai alocar uma
matriz na pilha não, só um ponteiro. Se você prefere:
int* opt_bin( const T(&rf)[M][N] )
Não vai mudar quase nada. Apenas que ao invés de escrever "(*rf)[i][j]" só
vai precisar escrever "rf[i][j]". Neste caso (para simplificar a escrita) eu
concordo que a referência é melhor que o ponteiro. Como comecei meus estudos
com o ANSI-C estou mais acostumado a trabalhar com ponteiros que com
referências.
E o ponteiro retornado desta versão em C++ seria perfeitamente compatível
com a versão em C.
Dizer que "não faz sentido" sem primeiro testar se funciona ou não é meio
agressivo não é? Só quis mostrar que existem outras soluções além de uma
classe matrix, gostar ou não já é outra história.
Asseguir a função refeita com template:
template <typename T, size_t M, size_t N>
int* opt_bin( const T(&rf)[M][N] )
{
size_t i, j, k;
int (*best)[M+1][N+1];
T cost[M+1][N+1], t;
best = (int (*)[M+1][N+1])new int[(M+1)*(N+1)];
for(i=0;i<N;i++)
for(j=(i+1);j<(N+1);j++)
cost[i][j] = MAX_FREQ;
for(i=0;i<N;i++) cost[i][i] = rf[0][i];
for(i=0;i<(N+1);i++) cost[i][i-1] = 0;
for(j=1;j<N;j++) {
for(i=1;i<=(N-j);i++) {
for(k=i;k<=(i+j);k++) {
t = cost[i][k-1] + cost[k+1][i+j];
if ( t < cost[i][i+j] ) {
cost[i][i+j] = t;
(*best)[i][i+j] = k;
}
}
t = 0;
for(k=i;k<=(i+j);k++) t = t + rf[0][k];
cost[i][i+j] = cost[i][i+j] + t;
}
}
return (int*)best;
}
Tudo bem, esta parte eu não havia entendido, pensei que 'rf' fosse realmente
uma matriz quadrada.
Então temos duas soluções:
template <typename T, size_t N>
int* opt_bin( const T(&rf)[N] )
{
int (*best)[N+1][N+1];
T cost[N+1][N+1], t;
best = (int (*)[N+1][N+1])new int[(N+1)*(N+1)];
...
for(i=0;i<N;i++) cost[i][i] = rf[i];
...
return (int*)best;
}
se, por exemplo, o vetor foi declarado:
double vetor[4];
Ou então podemos fazer assim, se o vetor original foi alocado dinamicamente:
int* opt_bin( const double *rf, int n )
{
double **cost;
int **best;
cost = new double*[n+1];
cost[0] = new double[(n+1)*(n+1)];
best = new int*[n+1];
best[0] = new int[(n+1)*(n+1)];
for(i=1;i<=n;i++) {
{ cost[i] = cost[i-1]+(n+1);
best[i] = best[i-1]+(n+1);
}
...
for(i=0;i<n;i++) cost[i][i] = rf[i];
...
delete[] cost[0];
delete[] cost;
int *result = best[0];
delete[] best;
return result;
}
Desta maneira não vai ser necessário fazer 2*(n+2) alocações, serão sempre
quatro, e o ponteiro retornado será compatível com a versão em C. Também
poderíamos modificar a função para:
int** opt_bin( const double* rf, int n )
{
...
delete[] cost[0];
delete[] cost;
return best;
}
O que facilitaria a interpretação do retorno da função.