Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

1. Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Jóvio
Jovioluiz

(usa Ubuntu)

Enviado em 24/03/2018 - 12:18h

Pessoal se puderem me ajudar. O problema é o seguinte:
Crie uma função que receba como parâmetros dois vetores de inteiros, v1 e v2, e as suas
respectivas quantidades de elementos, n1 e n2. A função deverá retornar um ponteiro para
um terceiro vetor, v3, com capacidade para (n1 + n2) elementos, alocado dinamicamente,
contendo a união de v1 e v2. Em seguida, crie a função principal do programa para chamar a função união passando dois
vetores informados pelo usuário (ou declarados estaticamente). Em seguida, o programa
deve exibir na tela os elementos do vetor resultante. O cabeçalho dessa função deverá ser o seguinte:
int* uniao(int *v1, int n1, int *v2, int n2);

O meu problema é que não estou conseguindo atribuir os valores dos vetores v1 e v2 para o vetor v3 com essa atribuição: (v3+i) = *(v1+i);

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

int* uniao(int *v1, int n1, int *v2, int n2){
int soma = n1 + n2;
int i=0, j=0;
int *v3 = (int *) malloc(soma * sizeof(int));

for(i=0; i<3; i++){
(v3+i) = *(v1+i);
}

for(i=3; i<6; i++){
(v3+i) = *(v2+i-3);
}

int temp = v3[0];
for(i=0; i<3; i++){
for(j=i; j<6; j++){
if((v3+j) < (v3+i)){
temp = (v3+i);
(v3+j) = (v3+i);
(v3+i) = temp;
}
}
}
}

int main(){

int v1[3], v2[3], v3[6], n1, n2;

for(int i=0; i<3; i++){
printf("Digite os valores para o vetor 1: ");
scanf("%d", (v1+i));
}

for(int i=0; i<3; i++){
printf("Digite os valores para o vetor 2: ");
scanf("%d", (v2+i));
}

uniao(v1, 3, v2, 3);

for(int i=0; i<3; i++){
printf("%d\n", *(v3+i));
}

free(v3);

}



  


2. MELHOR RESPOSTA

Hugo Cerqueira
hrcerq

(usa Outra)

Enviado em 24/03/2018 - 15:52h

Jovioluiz escreveu:

O meu problema é que não estou conseguindo atribuir os valores dos vetores v1 e v2 para o vetor v3 com essa atribuição: (v3+i) = *(v1+i);


Isso acontece porque você tratou v3 como se fosse um valor e não um ponteiro. A resposta está no seu próprio código, veja que a expressão "*(v1+i)" está correta.

Explico: vamos supor que o vetor v1 tem 3 posições, e vamos supor também que a primeira posição dele está no endereço de memória 0x103 (apenas um exemplo). Isso significa que a segunda posição (isto é, do segundo elemento) está em 0x103 + tamanho de um int. Se o tamanho de um int para o seu compilador for 4 bytes, por exemplo, então a segunda posição estará em 0x107, e a terceira em 0x10b.

Quando você digita a expressão "v1" está se referindo a "&v1[0]", isto é, o endereço de memória da primeira posição de v1 (0x103). Porém os ponteiros em C são inteligentes, se você soma 1 a um ponteiro, ele entende que deve somar na verdade a quantidade de bytes do tipo em questão. Nesse caso o tipo é int, então ele somará mais 4 posições ao ponteiro para chegar ao segundo elemento. Portanto (&v1[0] + 1) = (v1 + 1) = 0x103 + 4 = 0x107. Se isso parece complexo, tente exercitar isso um pouco, coloque numa folha de papel (ou num editor de texto) etapa por etapa.

Dessa forma, quando você diz "*(v1 + i)", está dizendo que se refere ao valor contido no endereço v1 + i. Sem o sinal de derreferenciamento (*) estaria se referindo ao endereço. "*" significa que você quer o valor contido no endereço e não o endereço em si.

Entendido isso, veja que você não aplicou esse mesmo sinal para v3:

(v3+i) = *(v1+i); 


E vou aproveitar pra sinalizar outro problema no seu código: na função uniao, você fez 3 loops for, considerando i = 3 no primeiro e i = 6 no segundo, e no terceiro i = 3 e j = 6. Isso significa que a função só vai funcionar se o primeiro vetor tiver 3 posições e o segundo tiver 6 posições. Experimente mudar o tamanho desses vetores na função main, e veja o que acontece.

Portanto, deve substituir esses valores por variáveis (que você já tem no programa). O valor 3 deve ser substituído pelo tamanho do primeiro vetor, e o valor 6 deve ser substituído pelo tamanho da união subtraindo o tamanho do primeiro vetor. Corrigindo isso, experimente alterar o tamanho dos vetores novamente e veja o resultado.

---

Atenciosamente,
Hugo Cerqueira

3. Re: Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Jóvio
Jovioluiz

(usa Ubuntu)

Enviado em 24/03/2018 - 16:30h

Prezado Hugo,
Eu fiz alguns ajustes no código como você comentou eliminando os 4 for e deixando dois for para preencher o vetor "v3"(não sei se está correto assim), mas outra duvida é como eu faço para passar o vetor v3 da função união para a main e como eu libero a memória alocada no final do programa.

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

int* uniao(int *v1, int n1, int *v2, int n2){

int soma = n1 + n2;
int i=0, j=0;
int *v3 = (int *) malloc(soma * sizeof(int));


for(i = 0; i < n1; i++){
*(v3+i) = *(v1+i);
}
for(i = 3; i < (soma-n1); i++){
*(v3+i) = *(v2+i);
}

/*for(i=0; i<3; i++){
*(v3+i) = *(v1+i);
}

for(i=3; i<6; i++){
*(v3+i) = *(v2+i-3);
}

int temp = v3[0];
for(i=0; i<3; i++){
for(j=i; j<6; j++){
if((v3+j) < (v3+i)){
temp = *(v3+i);
*(v3+j) = *(v3+i);
*(v3+i) = temp;
}
}
}*/
}

int main(){

int v1[3], v2[3], v3[9], n1, n2;


for(int i=0; i<3; i++){
printf("Digite os valores para o vetor 1: ");
scanf("%d", (v1+i));
}

for(int i=0; i<3; i++){
printf("Digite os valores para o vetor 2: ");
scanf("%d", (v2+i));
}

uniao(v1, 3, v2, 3);

for(int i=0; i<6; i++){
printf("%d\n", *(v3+i));
}

free(v3);

}



4. Re: Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Hugo Cerqueira
hrcerq

(usa Outra)

Enviado em 24/03/2018 - 16:52h

O ajuste que você fez para os loops está correto. Sobre a passagem do vetor para a função main, é simples: como você retorna um valor de uma função para outra função? Usando o comando return. Inclusive foi bom você perguntar isso porque eu não tinha reparado que o retorno da função união (int *) não é compatível com o que efetivamente está sendo retornado por ela (void).

O retorno da função deve ser sempre compatível com a declaração da função. Dessa forma a função int* uniao(int *v1, int n1, int *v2, int n2) obrigatoriamente tem que receber os valores entre parênteses e obrigatoriamente tem que retornar um ponteiro para um valor inteiro (int *). Esse ponteiro, será a primeira posição do vetor v3. Isso deve ser informado no comando return. Essa ação é perfeitamente legal, visto que o vetor v3 foi alocado dinamicamente (no espaço heap, via malloc). É importante lembrar que você não deve retornar um ponteiro para um endereço de memória estático, isto é, não alocado no heap.

Dessa forma, quando você chamar a função uniao dentro da função main, deverá guardar um resultado em um ponteiro criado na função main, como por exemplo:

int *v3 = 0;
v3 = uniao(v1, 3, v2, 3);


Assim você conseguirá acessar o vetor pela variável "v3", que é um ponteiro. Note que é boa prática definir explicitamente um valor para um ponteiro. O valor 0 quer dizer que ele não aponta para lugar nenhum, e assim você evita que ele guarde algum endereço de memória aleatório. Isso garante que ele permaneça assim até receber um endereço que você realmente quer guardar nele, como o resultado da função uniao nesse exemplo.

Para liberar a memória alocada, deverá usar a função free, como já está fazendo. O que vai mudar é que você não vai criar um vetor v3 com posições já pré-definidas como fez no início da função, e sim um ponteiro para um bloco de memória a ser recebido depois.

---

Atenciosamente,
Hugo Cerqueira


5. Re: Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Jóvio
Jovioluiz

(usa Ubuntu)

Enviado em 24/03/2018 - 17:39h

Muito obrigado Hugo pela sua ajuda. Só tem mais um problema na hora de imprimir os valores correspondente ao vetor v2 que está imprimindo lixo de memória, mas o resto está ok.

Muito Obrigado.


6. Re: Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Hugo Cerqueira
hrcerq

(usa Outra)

Enviado em 24/03/2018 - 20:42h

Pois bem,

Confesso que eu não dei a devida atenção ao problema e cometi alguns erros na hora de te passar a solução, mas agora analisei com mais calma e vou apontar esses erros:

1. Falei sobre substituir no segundo laço for da função uniao o valor pelo tamanho total - n1, que nada mais é que n2. Mas na verdade deve ser apenas o tamanho total, já que vai começar a iterar a partir do tamanho de n1 (que pode inclusive ser maior que n2).

2. Outra sugestão que não fiz foi: definir na função main valores fixos para o tamanho dos vetores. Você pode fazer isso com a expressão const, veja:

const int n1 = 3;
int v1[n1];


Assim, se tiver que mudar depois o tamanho do vetor, poderá fazê-lo em um lugar só. Mas lembre-se de usar essa variável em todos os lugares da função main em que tiver que se referir ao tamanho do vetor.

3. Sobre os valores de v2 que não aparecem corretamente, você não deve usar a variável i para computar a cópia dos valores de v2 para v3. Em vez disso, use a variável j, adaptando o laço for para isso:

for(i = n1, j = 0; i < soma; i++, j++)
{
*(v3+i) = *(v2+j);
}


Peço desculpas pelos erros, espero não ter feito você perder muito tempo por causa disso.

---

Atenciosamente,
Hugo Cerqueira


7. Re: Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Jóvio
Jovioluiz

(usa Ubuntu)

Enviado em 25/03/2018 - 11:33h

Foi de uma grande ajuda sua e não fez perder meu tempo. Eu notei também que no segundo laço for tinha que ser o tamanho total. Outra dica sua de definir uma constante com valores fixos eu fiz um pouco diferente usando o #define MAX 3 no cabeçalho do programa e não sei se isso é a melhor forma, mas eu altero somente ali.
Agradeço pela ajuda e abraços.


8. Re: Acessar as posições dos elementos através de seus endereços de memória [RESOLVIDO]

Hugo Cerqueira
hrcerq

(usa Outra)

Enviado em 25/03/2018 - 18:06h

Jovioluiz escreveu:

[...] Outra dica sua de definir uma constante com valores fixos eu fiz um pouco diferente usando o #define MAX 3 no cabeçalho do programa e não sei se isso é a melhor forma, mas eu altero somente ali. [...]


O que você fez nesse caso foi usar uma diretiva de pré-processamento. Antes de o programa ser compilado, todo o código-fonte passa por alguns ajustes pelo pré-processador. As diretivas #include, por exemplo, servem para adicionar os cabeçalhos das bibliotecas que você usa ao seu programa. Com isso você evita ter que digitar esses cabeçalhos toda vez que cria um programa, já que a diretiva #include é muito mais prática, além de reduzir a chance de erros. Já a diretiva #define que você usou, serve para substituir todas as ocorrências de um termo por outro (isso ocorre independentemente da sintaxe C).

Depois que as constantes (const) foram incorporadas à linguagem C, o uso de #define caiu bastante. É arriscado dizer que uma forma ou outra é a melhor porque tudo varia muito de um contexto pra outro mas em geral esse método (#define) tem sido evitado pelos programadores por ter uma tendência um pouco maior a introduzir bugs no programa.

---

Atenciosamente,
Hugo Cerqueira






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts