Присвоение массива структуры указателю - PullRequest
2 голосов
/ 30 января 2011

Я инициализировал массив структур (содержащий только строку символов с именем name. Затем этот массив структур присваивается указателю, например так:

location locations[2] = {{"Padstow", 50.5384, -4.9378}, 
                         {"Newquay", 50.412, -5.0757}};

int location_size = 2;

location *loc_ptr;
loc_ptr = &locations[0];

// pick an element to remove
location element = loc_ptr[1];

remove_element(loc_ptr, location_size, element);

Затем я передаю этот указатель вФункция. Внутри этой функции я удаляю элемент массива. Это делается путем итерации текущего массива и создания нового массива. Новый массив содержит ожидаемые данные.

Внутри remove_element function:

void remove_element(location *ptr, int count, location element) {

    // create the new array
    location new_locations[count-1];

    // go through and pick out the non-matching element

    // create the new pointer        
    location *new_ptr;
    new_ptr = &new_locations[0];

    // assign the new array to the original pointer
    ptr = new_ptr;
}    

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

Ответы [ 6 ]

2 голосов
/ 30 января 2011

Я давно ничего не делал в C, так что я немного заржавел, но попробую ...

Я вижу, что есть (по крайней мере) два способа заставить это работать: либо вернуть новый указатель для нового массива из функции и сохранить его в старом указателе, что-то вроде (это может быть синтаксически некорректно):

loc_ptr = someFunctionCreatingTheNewArrayAndReturningAPointerToIt(loc_ptr);

Другая возможность - передать loc_ptr в функцию-указатель вместо значения-значения. По сути, вы передадите «указатель-указатель» в качестве параметра в функцию, указатель-указатель будет указывать на вас loc_ptr. Внутри функции вы разыменовываете адрес памяти массивов от указателя к указателю для доступа к исходному массиву. После того, как вы создали и заполнили новый массив, поместите адрес памяти нового массива в параметр, передаваемый по указателю.

Edit: я кратко описал оба способа, это на самом деле в C ++, но я на 99% уверен, что указатели работают в C одинаково (извините, если это немного многословно). Обратите внимание, что массивы нигде не освобождаются, поэтому это может привести к утечкам памяти (но вы должны получить представление о передаче по значению и по указателю):

#include <iostream>
#include <string.h>

struct location
{
    std::string name;
    double lat;
    double lon;
};

location* createNewArrayAndReturnPointer(location* loc)
{
    std::cout << "-- Replacing array, name of the first location in old array is " + loc->name << std::endl;
    location* newLoc = new location[2]; //Local pointer-variable, creating new array and storing array address to it
    newLoc[0].name = "Replacing pointer by return value";

    return newLoc;  //Return new pointer
}

void modifyViaGivenPointerToPointer(location** loc_ptr_to_ptr)
{
    location* loc = *loc_ptr_to_ptr;    //De-referencing the array address from the pointer-to-pointer, storing to local pointer-variable
    std::cout << "--  Modifying pointer, name of the first location pointed originally is " + loc->name << std::endl;

    location* newLoc = new location[2]; //Creating new array and storing to local pointer-variable
    newLoc[0].name = "From modifyViaGivenPointerToPointer";
    *loc_ptr_to_ptr = newLoc;   //Replacing the contents of given pointer-variable via dereference

}

void printNameOfFirstLocationInArray(location* loc_ptr)
{
    std::cout << "The name of the first location pointer by loc_ptr is now " << loc_ptr->name << std::endl;
}

int main(void)
{
    location locations[2] = {{"Padstow", 50.5384, -4.9378},
                             {"Newquay", 50.412, -5.0757}};

    location* loc_ptr;
    loc_ptr = &locations[0];

    printNameOfFirstLocationInArray(loc_ptr);

    //Returns new pointer from function and store it in the pointer-variable
    loc_ptr = createNewArrayAndReturnPointer(loc_ptr);
    printNameOfFirstLocationInArray(loc_ptr);

    //Modifies the passed pointer-to-pointer, so it points to the new array after returning
    modifyViaGivenPointerToPointer(&loc_ptr);
    printNameOfFirstLocationInArray(loc_ptr);

    return 0;
}

Вывод:

Имя первого указателя местоположения от loc_ptr теперь Padstow
- При замене массива имя первого расположения в старом массиве - Padstow
Имя первого указателя местоположения от loc_ptr теперь заменяет указатель на возвращаемое значение
- Модифицирующий указатель, имя первого местоположения, на которое указывалось изначально, заменяет указатель на возвращаемое значение
Имя первого указателя местоположения от loc_ptr теперь: от modifyViaGivenPointerToPointer

1 голос
/ 30 января 2011

Я предполагаю, что вы делаете что-то порядка

void f(location *loc_ptr)
{
   location *new_array = ...
   loc_ptr = new_array;
}

int main(void)
{
  location locations[2] = {...};
  location *loc_ptr = locations;
  f(loc_ptr);
  ...
}

Если это так, решение

void f(location **loc_ptr)
{
  location *new_array = ...;
  *loc_ptr = new_array;
}

int main(void)
{
  location locations[2] = {...};
  location *loc_ptr = locations;
  f(&loc_ptr);
  ...
}

Если вы хотите изменить значение loc_ptr, а не то, на которое указывает loc_ptr, вы должны передать указатель на него функции.

1 голос
/ 30 января 2011

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

Будьте очень осторожны, чтобы длины массивов были одинаковыми, ИЛИ всегда поддерживайте переменную длины массива где-то, что НИКОГДА НЕ ВЫРАЩАЕТСЯ. C массивы не растут. Вы можете попробовать увеличить его с помощью realloc(3), но он может потерпеть неудачу, и оригинал должен быть выделен с malloc(3) в первую очередь. Они могут уменьшаться, если вы просто притворяетесь, что они короче ... :)

1 голос
/ 30 января 2011

Когда вы делаете

ptr = new_ptr;

Я предполагаю, что ptr - это параметр вашей функции. На самом деле вы переопределяете значение в стеке (значение самого указателя), что не изменит значение указателя вне функции. Вы можете либо передать обратно новый указатель, либо взять в качестве аргумента двойной указатель на «location», а затем выполнить:

*p_ptr = new_ptr;
1 голос
/ 30 января 2011

Если у вас есть:

struct location a;
struct location b;

a = b;

, вы сделаете копию данных в b в a.

Вы, кажется, делаете следующее:

struct location *a;
struct location *b;

a = b;

Копирует указатель из b в a;а не данные.

Возможно, вы имеете в виду:

*ptr = *new_ptr;

Чтобы скопировать данные, на которые указывает new_ptr, в местоположение, на которое указывает ptr.

1 голос
/ 30 января 2011

Как вы возвращаете новый массив из вашей функции.

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

Это не сработает:

void f(location *l)
{
   // changing the array here:
   l = malloc(5*(sizeof(location));
   // add new stuff to l
}

int main()
{
    location *loc_ptr;
    loc_ptr = &locations[0];
    f(loc_ptr); // won't change address loc_ptr's is pointing to.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...