Copiando vetores em C

9 respostas
J

Oi…Não tenho familiaridade com C. Surgiu uma dúvida enquanto eu estava desenvolvendo uma função aqui.

Eu queria receber um vetor de inteiros como parâmetro e retornar um vetor resultante da manipulação do primeiro, mas sem modificar o primeiro. Para isso, iamgino, tenho que fazer uma cópia de vetores. Fiz um exemplo ilustrativo do que eu queria fazer. Segue:

int* manipula_vetor3(int v[],int n,int a) { int i; int vetorModificado[n]; for(i=0;i<n;i++) { vetorModificado[i] = v[i]+(*a); printf("%i\t",vetorModificado[i]); } return vetorModificado; }

Mas eu sei que não posso declarar um vetor dinamicamente em C, como fiz em ( int vetorModificado[n];)…Alguém sabe como posso resolver esta questão?

9 Respostas

P

eu receberia 2 ponteiros, a origem e o destino e mais o tamanho e iteraria sobre o primeiro copiando para o segundo.

J

Declarando o parâmetro formal como cons dá um erro de compilação quando chamo a função na main. Estou chamando assim na main:

int v[5] = { 4, 6, 5 , 7 , 2} ;
int vetor2[5];
int resultado;
int a =  3;
    
vetor2 = manipula_vetor3(v,5,a);

O erro é: Incompatible types in assingnment of 'int' to 'int[5]'

E

ou, voce pode alocar o vetor dinamicamente:

int* manipula_vetor3(int v[],int  n,int a)  
  {  
        int i;  
        int *vetorModificado; 
        vetorModificado = (int *) malloc(sizeof(int) * n);
        for(i=0;i<n;i++)  
        {  
             vetorModificado[i] = v[i]+(*a);  
             printf("%i\t",vetorModificado[i]);  
                    }  
                    return vetorModificado;  
  }
E
#include <stdlib.h>
#include <stdio.h>

/* A macro a seguir determina a dimensão de um vetor em elementos.
   Não pode ser usada com vetores alocados dinamicamente */
#define DIM(v) \
    (sizeof(v) / sizeof(v[0]))

int* transformar (int vect[], size_t n, int valor) {
    int* ret = malloc (sizeof(int) * n);
    int i;
    for (i = 0; i < n; ++i) {
        ret[i] = vect[i] + valor;
    }
    return ret;
}

void print (const char* texto, int vetor[], int n) {
    int i;
    puts (texto);
    for (i = 0; i < n; ++i) {
        printf ("%d, ", vetor[i]);
    }
    puts ("");
}

int main (int argc, char *argv[]) {
    int vect[10];
    int *vect2;
    int i;
    for (i = 0; i < DIM(vect); ++i) { 
        vect[i] = 15 * i;
    }
    vect2 = transformar (vect, DIM(vect), 20);
    print ("Vetor original", vect, DIM(vect));
    print ("Vetor transformado", vect2, DIM(vect));
    free (vect2);
}
E
Jokabeludoido:
int v[5] = { 4, 6, 5 , 7 , 2} ;
int vetor2[5];
int resultado;
int a =  3;
    
vetor2 = manipula_vetor3(v,5,a);

O erro é: Incompatible types in assingnment of 'int' to 'int[5]'

Você não pode copiar um vetor no outro assim sem mais nem menos. Você pode usar memcpy se quiser.

Outra coisa, você NUNCA deve retornar o endereço de um array ou variável local em C; isso vai provocar problemas rapidamente. Um erro muito comum é fazer exatamente isto aqui:

int * ingenuo() {
    int x[5];
    return x;
}

Note que quando o método "ingenuo" retorna, a variável "x", que foi alocada na pilha, está inválida. Pode até ser que, por acaso, alguns dos valores de x estejam ainda corretos quando você for usar, mas na verdade, como essa memória já pode ter sido sobreescrita por outro método, você possa vir a ter um problema muito sério. Cuidado! cuidado! cuidado!

J
entanglement:
Jokabeludoido:
int v[5] = { 4, 6, 5 , 7 , 2} ;
int vetor2[5];
int resultado;
int a =  3;
    
vetor2 = manipula_vetor3(v,5,a);

O erro é: Incompatible types in assingnment of 'int' to 'int[5]'

Você não pode copiar um vetor no outro assim sem mais nem menos. Você pode usar memcpy se quiser.

Outra coisa, você NUNCA deve retornar o endereço de um array ou variável local em C; isso vai provocar problemas rapidamente. Um erro muito comum é fazer exatamente isto aqui:

int * ingenuo() {
    int x[5];
    return x;
}

Note que quando o método "ingenuo" retorna, a variável "x", que foi alocada na pilha, está inválida. Pode até ser que, por acaso, alguns dos valores de x estejam ainda corretos quando você for usar, mas na verdade, como essa memória já pode ter sido sobreescrita por outro método, você possa vir a ter um problema muito sério. Cuidado! cuidado! cuidado!

Pois é...Era exatamente esta a questão. Eu recebi um código em mãos em que o sujeito fez algo assim e disse que tem certeza que funciona. Eu imaginei que exstissem problemas associados a esta forma de fazer, mas não sabia quais.

Deixa eu ver se entendi. Retornando o ponteiro para o arranjo declarado dentro do escopo da função, não há garantias de que, voltando ao escopo global, os valores estejam lá de fato. Eles podem ser alterados por outro processo ou procedimento neste meio tempo. É iso?

L

memcpy() do header <string.h>

int vetorModificado[n];
memcpy(vetorModificado, v, n * sizeof(int));
E

Jokabeludoido:

Deixa eu ver se entendi. Retornando o ponteiro para o arranjo declarado dentro do escopo da função, não há garantias de que, voltando ao escopo global, os valores estejam lá de fato. Eles podem ser alterados por outro processo ou procedimento neste meio tempo. É iso?

Sim senhor. Vou fabricar um exemplo para você ter exatamente uma idéia do que ocorre.

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


int *ingenuo (int x) {
    int var [10];
    int i;
    for (i = 0; i < sizeof(var) / sizeof(var[0]); ++i) 
        var[i] = x;
    return var;    /* nunca retorne o endereço de um array local! */
    /* O Microsoft C dá até uma mensagem "warning C4172: returning address of local variable  or temporary */
}

double* esperto (double x) {
    double var [5];
    double *ret;
    int i;
    for (i = 0; i < sizeof(var) / sizeof(var[0]); i++) 
       var[i] = x;
    ret = (double *) calloc (sizeof(var)/sizeof(var[0]), sizeof(var[0]));
    memcpy (ret, var, sizeof(var));
    return ret;
}

void print (const char* msg, int elementos[], int n) {
    int i;
    puts (msg);
    for (i = 0; i < n; ++i) 
        printf ("%d, ", elementos[i]);
    puts("");
}

main (int argc, char*argv[]) {
    int* elementos;
    double* outros_elementos;
    elementos = ingenuo (10);
    print ("Depois do retorno de ingenuo:", elementos, 10);
    outros_elementos = esperto (2.7182818284590452353602874713527);
    print ("Depois do retorno de esperto:", elementos, 10);
    free (outros_elementos); /* tudo que alocar, desaloque */
}

O que você esperaria que ele imprimisse para o valor retornado por “ingenuo”? Seria “10, 10, 10, 10, 10, 10, 10, 10, 10, 10,”.
Só que ele imprime, dependendo da opção de compilação:

Depois do retorno de ingenuo:
10, 4208064, -208566343, -2, 4200412, 4198670, 4354048, 4354048, 8, 1245040,
Depois do retorno de esperto:
-[telefone removido], 4208064, -208566343, -2, 4200412, 4198670, 4354048, 4354048, 8, 1245040,

ou então

Depois do retorno de ingenuo:
10, 4205888, -[telefone removido], -2, 4200252, 4198622, 4255744, 4255744, 8, 1245040,
Depois do retorno de esperto:
-[telefone removido], 4205888, -[telefone removido], -2, 4200252, 4198622, 4255744, 4255744, 8, 12
45040,

ou ainda outra coisa qualquer (compile esse código com algum outro compilador, que você vai ver ainda outros resultados diferentes.)
Mude alguma opção de compilação (tire ou ponha o modo debug, use otimização ou não, etc.
E vai ver ainda outros resultados bizarros.

Portanto, certos warnings são na verdade erros, e muito graves. Esse é um deles.

G

Ei Jokabeludoido

Este livro é muito bom e explica muito bem essas tretas dos ponteiros e arrays em C: Prentice_Hall-Expert_C_Programming_Deep_Secrets

Criado 29 de junho de 2010
Ultima resposta 2 de jul. de 2010
Respostas 9
Participantes 6