2016-12-29 10 views
-1

Как сказано в заголовке, у меня есть вопрос относительно использования * дважды, как в основной функции следующего кода. он работает, но я не понимаю, почему использование ** здесь. То, что я хочу, это массив SPPoints, размер n, где parr - базовый адрес. Почему ** правильно и * неправильно в этом случае? Благодарю.C, в отношении указателей (или указателей на указатели?), ** и malloc

код SPPoint:

struct sp_point_t 
{ 
    double* data; 
    int dim; 
    int index; 
}; 

SPPoint* spPointCreate(double* data, int dim, int index) 
{ 
    if (data == NULL || dim <= 0 || index < 0) 
    { 
     return NULL; 
    } 
    SPPoint* point = malloc(sizeof(*point)); 
    if (point == NULL) 
    { 
     return NULL; 
    } 
    point->data = (double*)malloc(dim * sizeof(*data)); 
    for (int i = 0; i < dim; i++) 
    { 
     point->data[i] = data[i]; 
    } 
    point->dim = dim; 
    point->index = index; 
    return point; 
} 

И это главная функция:

int main() 
{ 
    int n, d, k; 
    scanf("%d %d %d", &n, &d, &k); 
    double* darr = malloc(d * sizeof(double)); 
    if (darr == NULL) 
    { 
     return 0; 
    } 
    SPPoint** parr = malloc(n * sizeof(SPPoint*)); 
    if (parr == NULL) 
    { 
     return 0; 
    } 
    for (int i = 0; i < n; i++) 
    { 
     for (int j = 0; j < d; j++) 
     { 
      scanf(" %lf", &darr[j]); 
     } 
     parr[i] = spPointCreate(darr, d, i); 
    } 
} 
+0

'SPPoint ** parr;' является указателем на указатель (ы) массива – wildplasser

+0

'SPPoint * spPointCreate (...)' BTW: SPPoint is * not * typedeffed. Вы используете компилятор C++? – wildplasser

+0

Это в файле заголовка, извините за то, что не в том числе. – Gray

ответ

-1

Массив может вести себя так же, как указатель. Например, int a [] очень похож на int * a. Каждая функция в SPPoint возвращает указатель на структуру SPPoint. Массив указателей на SPPoint может быть записан как указатель на указатель на SPPoint. С помощью команды malloc вы назначаете определенный объем памяти (достаточно, чтобы удерживать n указателей на SPPoint) для хранения указателей на структуры SPPoint.

Не все указатели являются массивами. SPPoint ** parr действует как указатель на массив, содержащий одиночные структуры типа SPPoint.

Массивы могут вести себя иначе, чем указатели, особенно при использовании для строк.

Причина, по которой выгодно использовать указатели на SPPoint (как и сейчас), заключается в том, что вы можете просматривать или изменять один элемент без необходимости копировать всю структуру.

+0

Очень хороший ответ, спасибо. – Gray

+0

добро пожаловать! – Rusty

+3

Массив нельзя рассматривать как указатель, не более, чем int можно рассматривать как двойной –

0

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

Таким образом, для динамически выделяемого массива SPPoint *, как у вас есть в вашем коде, указатель на первый из тех, кто имеет тип SPPoint * *

Ваш существующий код создает массив SPPoint *, то есть массив указателей. Каждый из этих указателей указывает на один динамически распределенный экземпляр SPPoint, то есть у вас есть отдельные распределения для каждой записи.

Это жизнеспособно, но вы указываете, что вам нужен массив SPPoint, и в этом случае указатель на первый элемент имеет тип SPPoint *.

Чтобы иметь такой массив, это единое распределение памяти. Поэтому вам нужно будет отредактировать функцию spPointCreate. В настоящее время выделяет память и инициализирует только один SPPoint. Вместо этого вы хотите отделить выделение от инициализации, поскольку вам нужно только одно выделение, но вам нужно несколько инициализаций. Ваша логика программы будет читать что-то вроде:

  • Выделяет один блок памяти, достаточно большой для nSPPoint s
  • Инициализировать каждый SPPoint внутри выделенного пространства

Если вы попробовали это, но застряли тогда отправьте новый вопрос с указанием кода и объясните, где вы застряли.