2011-01-30 2 views
2

Я инициализируется массив структур (содержащих только строку символов, называемое 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 :

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; 
}  

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

+0

Пожалуйста, добавьте следующее к вашему вопросу. Как вы создаете новый массив в функции? Как вы возвращаете созданный массив из этой функции? Было бы неплохо, если бы вы просто опубликовали код функции, заменив все нерелевантные коды на короткие комментарии, например '// modify array '. Кроме того, вы упоминаете 'ptr' только один раз, и вы не объяснили, откуда оно взялось. Сначала у вас был 'loc_ptr'. –

ответ

2

Я ничего не сделал в C долгое время, так что я немного ржавый, но я дам ему попробовать ...

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

loc_ptr = someFunctionCreatingTheNewArrayAndReturningAPointerToIt(loc_ptr);

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

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

#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 теперь Замена указателя на возвращаемого значения
- Изменение указателя, n AME первого места заостренного первоначально является замена указателя на возвращаемом значении
Имени первого указателя местоположения по loc_ptr теперь от modifyViaGivenPointerToPointer

+0

Я бы не сказал «по ссылке», когда говорил о C. Кто-то мог смутить его с помощью C++. Просто скажите «по указателю». –

+0

Правда, я отредактирую свой ответ – esaj

1

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

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

Это не будет работать:

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. 
} 
1

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

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

Но учтите, что C не имеет механизма для копирования _arrays_ вещей через одно назначение. – sarnold

+0

А, да, совершенно верно. Это копирует только один элемент, а не массив. – davidg

1

Когда вы

ptr = new_ptr; 

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

*p_ptr = new_ptr; 
1

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

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

+0

Функция удаляет элемент; поэтому мои намерения заключались в том, чтобы притворяться, что они становятся все меньше. – nickcharlton

1

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

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 указывает на, вы должны передать указатель на него функции.

Смежные вопросы