2013-06-27 4 views
0

указатели всегда получают меня в программировании на C.Как передать указатель на массив структур в функцию

У меня возникли проблемы, я хочу передать указатель на массив структур в функцию, чтобы он мог модифицировать структуры, а затем передать элементы массива позже в других функциях. Проблема в том, что, когда я думаю, что я индексирую массив и указываю его на модифицированную структуру, я пытаюсь посмотреть на членов позже, они не являются измененными значениями. Вот некоторые из моего кода

typedef struct 
{ 
    int rows; 
    int columns; 
    int *data; 
} Mat; 

int main(void) 
{ 
    Mat result, decoded_result; 
    int result_data[8] = 
    { 0, 0, 0, 0, 0, 0, 0, 0 }; 
    int decoded_data[4] = 
    { 0, 0, 0, 0 }; 
    result.columns = 1; 
    result.rows = 8; 
    result.data = &result_data[0]; 
    decoded_result.columns = 1; 
    decoded_result.rows = 4; 
    decoded_result.data = &decoded_data[0]; 

    Mat m1, m2, m3, m4, m5; 
    m1.rows = m2.rows = m3.rows = m4.rows = m5.rows = 4; 
    m1.columns = m2.columns = m3.columns = m4.columns = m5.columns = 1; 

    int md1[4], md2[4], md3[4], md4[4], md5[4]; 

    m1.data = &md1[0], m2.data = &md2[0], m3.data = &md3[0], m4.data = &md4[0], m5.data = 
     &md5[0]; 

    Mat mat_array[10] = 
    { m1, m2, m3, m4, m5 }; 

    decode_data(&result, &decoded_result, mat_array); 
    return 0; 
} 

int decode_data(Mat *result, Mat *decoded_result, Mat *mat_array) 
{ 
    int ii; 
    int size_of_EEPROM = 5; 
    //steps to decode data 
    for (ii = 0; ii < size_of_EEPROM; ii++) 
    { 
    decode(result, decoded_result); //decodes hamming 8,4, works 
    mat_array[ii] = *decoded_result; ///This is where the problem is 
    } 
    return 0; 
} 

Заранее спасибо за помощь с указателями :)

+1

Шаг Один: отступ/форматирования кода, так что легче читать. –

+1

Что вы смотрите после 'decode_data()'. Элементом 'mat_array' являются копии' m1, m2, ... ', поэтому последнее не изменится. –

+1

Это поможет, если вы закипите этот код дальше, чтобы он содержал только одну или две матрицы и ненужные петли или другие вещи. Вы также можете запустить свою программу под 'valgrind', если вы работаете в Linux, чтобы проверить наличие ошибок памяти - они слишком часто встречаются в этом типе кода. –

ответ

3

Как Mat несет указатель, просто присваивая Mat a до Mat b не будет работать. По крайней мере, не для данных, на которые ссылается Mat член data.

Что нужно сделать здесь, также называется Deep Copy. Глубокое копирование также создало бы копию того, на что ссылается data.

Ниже приведен пример того, как это можно сделать для Mat.

Примечание: Поскольку отрицательные строки и столбцы не использовать вы бы лучше объявить Mat так:

typedef struct 
{ 
    size_t rows; 
    size_t columns; 
    int * data; 
} Mat; 

(Как size_t определяется как unsigned такого рода заявления делает ненужным для проверки отрицательный значения, проведенные членами rows и columns до выделения новых данных, когда глубоко справляясь, как показано ниже)

#include <stdlib.h> /* for malloc(), size_t */ 
#include <string.h> /* for memcpy() */ 
#include <errno.h> /* for errno, ENOMEM, EINVAL */ 

... 

/* Deep-copies src to dst. */ 
/* Returns 0 on success or -1 on error. Sets errno in the latter case. */ 
int mat_copy(Mat * dst, const Mat * src) 
{ 
    if ((!dst) || (!src)) 
    { 
    errno = EINVAL; 
    return -1; 
    } 

    dst->rows = src->row; 
    dst->columns = src->columns 
    dst->data = NULL; 

    if (src->data) 
    { 
    size_t size = dst->rows * dst->columns * sizeof (*(dst->data)); 

    dst->data = malloc(size); 
    if (!dst->data) 
    { 
     errno = ENOMEM; 
     return -1; 
    } 

    memcpy(dst->data, src->data, size); 
    } 

    return 0; 
} 
-1

Существует правило трех в C++ при использовании указателей. В нем говорится, что если вам нужно одно из следующих, вам понадобятся другие два. Эти три являются Destructor/Copy Constructor/Assign Operator.

Так что происходит в вашем сценарии. Когда вы пишете mat_array [б] = * decoded_result он фактически делает:

mat_array[ii].rows = decoded_result.rows; 
mat_array[ii].columns = decoded_result.columns; 
mat_array[ii].data = decoded_result.data // here just assign pointers, not the entire data. 

В этом случае вы должны сделать оператор присваивания, чтобы сделать фактическую копию данных.

+2

Вопрос о C, а не C++. – interjay

+0

Те же правила там. Вы должны убедиться, что данные скопированы не только указатели. –

+0

Это может быть правдой, но это не имеет ничего общего с операторами присваивания и большинством других вещей, которые вы написали. – interjay