Ir ao conteúdo
  • Cadastre-se

C Matriz simétrica em C


Posts recomendados

Não sei o que está errado com o meu código. Não importa os valores que em entre na função atribui, o resultado sempre aparece "matriz simetrica". Preciso de ajuda! Me ajudem a corrigir essa código!

Acho que a função atribui está errada, mas não sei corrigir. Também não sei se a função libera está correta. Por favor, me ajudem!

 

Código:

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

struct mat {
	int dim;
	float* v;
};

typedef struct mat MatrizSimetrica;

MatrizSimetrica* cria (int n) {
	int s = n*(n+1)/2;
	MatrizSimetrica* mat = (MatrizSimetrica*) malloc(sizeof(MatrizSimetrica));
	mat->dim = n;
	mat->v = (float*) malloc(s*sizeof(float));
	return mat;
}

void libera (MatrizSimetrica* mat) {
	free(mat->v);
	free(mat);
}

float acessa (MatrizSimetrica* mat, int i, int j) {
	int k; /* indice do elemento no vetor */
	if (i<0 || i>=mat->dim || j<0 || j>=mat->dim) {
		printf("\nAcesso invalido.\n");
		exit(1);
	}
	if (i>=j)
		k = i*(i+1)/2 + j;
	else
		k = j*(j+1)/2 + i;
	return mat->v[k];
}

void atribui (MatrizSimetrica* mat, int i, int j, float v) {
	int k;
	if (i<0 || i>=mat->dim || j<0 || j>=mat->dim) {
		printf("\nAtribuicao invalida.\n");
	    exit(1);
    }
    k = i*mat->dim+j;
    mat->v[k] = v;
}

int main() {
	int i, j, k;
	
	MatrizSimetrica* mat = cria(2);
	
	atribui(mat, i, j, 1);
	atribui(mat, i, j, 2);
	atribui(mat, i, j, 4);
	atribui(mat, i, j, 7);

    if (acessa(mat, i, j) == mat->v[k]) {
		printf("matriz simetrica.\n");
	} else {
		printf("matriz nao simetrica.\n");
	}
	
	libera(mat);
	return 0;
}

 

Link para o comentário
Compartilhar em outros sites

@Antônio da Silva O código não está compilando, dá erro na linha do malloc. Veja que matsim (na linha do typedef) não existe, o nome da struct é mat e você pode resolver corrigindo para matsim.

 

struct matsim{
 int dim;
 float* v;
};

 

Em main as funções de atribuição estão recebendo as variáveis i e j, mas você só declarou e não iniciou e nem atribuiu nada a elas.

 

Outro ponto é na função cria que você faz um cálculo para alocar o tamanho do vetor e na função atribui você faz outro para pegar o índice, veja se não pode haver caso onde o índice seja maior que o tamanho alocado.

 

Para facilitar a ajuda poste a questão desse exercício.

Link para o comentário
Compartilhar em outros sites

@Midori A minha professora deu pronto as funções "cria" e "acessa" e mandou a gente criar as funções "libera" e "atribui" e chamar todas na main. O objetivo é ver se a matriz é simétrica ou não (na matriz simétrica, os elementos acima da diagonal principal devem ser iguais aos elementos abaixo da diagonal principal). O código tem que ser com vetor simples e alocação dinâmica. Eu não sei como corrigir.

Link para o comentário
Compartilhar em outros sites

@Antônio da Silva  Como a função cria está alocando metade dos elementos + diagonal (fórmula triangular), já é esperado que a matriz seja simétrica.

 

Na função atribui o valor de k não devia ser como na função acessa? Da forma que está se por exemplo você criar com n = 3, a alocação será para 6 elementos e se passar como argumento de atribui i = 2 e j = 2 o valor de k será 8 (maior que o limite alocado).

 

A função libera está correta.


Para chamar as funções em main você pode fazer algo assim,

 

int main() {
    MatrizSimetrica* mat = cria(2);
	
    atribui(mat, 0, 0, 1);
    atribui(mat, 0, 1, 2);
    atribui(mat, 1, 1, 4);

    printf("%f\n",acessa(mat, 0, 1));
    printf("%f\n",acessa(mat, 1, 0));
    
    libera(mat);
    return 0;
}

 

Link para o comentário
Compartilhar em outros sites

@Midori Muito obrigado pelas correções! Eu fiz algumas mudanças na função atribui e coloquei a main como você falou e o código ficou assim:

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

struct mat {
	int dim;
	float* v;
};

typedef struct mat MatrizSimetrica;

MatrizSimetrica* cria (int n) {
	int s = n*(n+1)/2;
	MatrizSimetrica* mat = (MatrizSimetrica*) malloc(sizeof(MatrizSimetrica));
	mat->dim = n;
	mat->v = (float*) malloc(s*sizeof(float));
	return mat;
}

void libera (MatrizSimetrica* mat) {
	free(mat->v);
	free(mat);
}

float acessa (MatrizSimetrica* mat, int i, int j) {
	int k; /* indice do elemento no vetor */
	if (i<0 || i>=mat->dim || j<0 || j>=mat->dim) {
		printf("\nAcesso invalido.\n");
		exit(1);
	}
	if (i>=j)
		k = i*(i+1)/2 + j;
	else
		k = j*(j+1)/2 + i;
	return mat->v[k];
}

void atribui (MatrizSimetrica* mat, int i, int j, float v) {
	int k;
	if (i<0 || i>=mat->dim || j<0 || j>=mat->dim) {
		printf("\nAtribuicao invalida.\n");
	    exit(1);
    }
    k = i*(i+1)/2 + j;
    mat->v[k];
}

int main() {
    MatrizSimetrica* mat = cria(2);
	
    atribui(mat, 0, 0, 1);
    atribui(mat, 0, 1, 2);
    atribui(mat, 1, 1, 4);

    if (acessa(mat, 0, 1) == mat->v[0]) {
        printf("matriz simetrica.\n");
    } else {
        printf("matriz nao simetrica.\n");
	}
	
    libera(mat);
    return 0;
}

Agora está exibindo "matriz nao simetrica". Eu fiquei um pouco confuso sobre n = 2 (no caso, com 4 elementos), mas eu só mandar 3 elementos para a função atribui. Não entendi direito isso de só alocar metade dos elementos + diagonal principal. Se no caso eu quisesse mandar mais elementos, como 8 por exemplo, qual deveria ser o valor de n?

 

Poderia, por gentileza, explicar melhor e ver se agora meu código está correto?

Link para o comentário
Compartilhar em outros sites

@Antônio da Silva  Veja que na função Cria o tamanho alocado é um número triangular: n(n + 1)/2

 

int s = n*(n+1)/2;
mat->v = (float*) malloc(s*sizeof(float));

 

Então se você passa n = 2 como argumento, a MatrizSimetrica vai alocar em v um vetor para 3 elementos (e não 4); Se n = 3, a alocação será de 6; n = 4, 10, etc.


A função só aloca para a diagonal e metade dos outros elementos,

tring.png.b8307f035b5f7e4bb639853b01957e56.png

 

 

Mas na função atribui você está atribuindo k = i*(i+1)/2 + j. Faça o cálculo veja que o k pode passar o limite alocado na função cria. Por isso você devia fazer como na função acessa,

 

if (i>=j)
    k = i*(i+1)/2 + j;
else
    k = j*(j+1)/2 + i;

 

Assim k sempre terá a posição correta da matriz e com a função acessa você pode fazer essa comparação para demonstrar a simetria (Matriz i,j = Matriz j,i)

 

if(acessa(mat, 0, 1) == acessa(mat, 1, 0))

 

Com n = 3, main poderia ser assim,

 

int main(){
    MatrizSimetrica* mat = cria(3);
	
    atribui(mat, 0, 0, 10);
    atribui(mat, 0, 1, 20);
    atribui(mat, 0, 2, 30);
    atribui(mat, 1, 1, 40);
    atribui(mat, 1, 2, 50);
    atribui(mat, 2, 2, 60);

    if(acessa(mat, 0, 2) == acessa(mat, 2, 0)){
        printf("matriz simetrica.\n");
    }else{
        printf("matriz nao simetrica.\n");
    }
    libera(mat);
    return 0;
}

 

Link para o comentário
Compartilhar em outros sites

@Midori Muito obrigado pela paciência em me explicar! Agora eu entendi melhor. Já coloquei na função atribui o mesmo cálculo da acessa e corrigi o if da main. Agora o programa exibe "matriz simetrica". O que eu não entendi muito bem foi o valor 0,1 sendo comparado com 1,0.

5 horas atrás, Midori disse:

if(acessa(mat, 0, 1) == acessa(mat, 1, 0))

Sei que isso é para comparar se a triangular superior é igual à inferior. Se for, a mensagem "matriz simetrica" deve ser exibida. Senão, a mensagem do else deve ser exibida. Porém, como o programa vai comparar o valor da posição 0,1 da matriz com o valor 1,0 se eu só estou informando o valor 0,1 (atribui(mat, 0, 1, 2);)?

 

Como o programa vai saber se o valor de 1,0 é ou igual ao valor 2 que eu estou passando para 0,1? Teria como me explicar isso, por gentileza? E se que quisesse criar uma situação na qual a mensagem exibida fosse a do else "matriz nao simetrica", quais valores eu deveria passar para atribui?

 

E se eu quisesse que o usuário entrasse com a valores, como eu deveria fazer?

Link para o comentário
Compartilhar em outros sites

 

1 hora atrás, Antônio da Silva disse:

Porém, como o programa vai comparar o valor da posição 0,1 da matriz com o valor 1,0 se eu só estou informando o valor 0,1 (atribui(mat, 0, 1, 2);)?

Como a matriz é simétrica a comparação Matriz 0,1 = Matriz 1,0 sempre será verdadeira. Veja que a função acessa faz o teste (i>=j) e sempre atribui a k o mesmo índice para o vetor. Dessa forma só retornaria matriz não simétrica se tivesse erro na programação (ou se tentar comparar outros índices como Matriz 0,1 com Matriz 1,1, mas não seria um "teste simétrico").

 

Então se não tiver erro na função quando você faz atribui(mat, 0, 1, 2) seria o mesmo que atribui(mat, 1, 0, 2).

 

Você pode pegar o trecho desse teste (i>=j) e ver como sempre retornará o mesmo índice, p.ex,

 

#include <stdio.h>

int indice(int i, int j){
    int k;
    
    if (i>=j){
        k = i*(i+1)/2 + j;
    }else{
        k = j*(j+1)/2 + i;
    }
    return k;
}

int main() {
    printf("%d, %d\n",indice(1,0), indice(0,1));
    printf("%d, %d\n",indice(2,1), indice(1,2));
    return 0;
}

 

Link para o comentário
Compartilhar em outros sites

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