开发者

Assigning struct array to pointer

开发者 https://www.devze.com 2023-02-08 01:01 出处:网络
I have initialised an array of structs (containing just a char string called name. This struct array is then assigned to a pointer, like so:

I have initialised an array of structs (containing just a char string called name. This struct array is then assigned to a pointer, like so:

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

I am then passing this pointer into a function. Inside this function, I am removing an element of the array. This is done by开发者_如何学JAVA iterating through the current array, and creating a new array. The new array contains the data I expect.

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

However, it is not changing the original data. Could you explain what I am doing incorrectly to assign this new array to my original pointer?


I haven't done anything in C for quite a while, so I'm a bit rusty, but I'll give it a try...

I'd see there are (at least) two ways to get this working: either return the new pointer for the new array from the function and store it in the old pointer, something like (this might be syntactically incorrect):

loc_ptr = someFunctionCreatingTheNewArrayAndReturningAPointerToIt(loc_ptr);

Another possibility is to pass the loc_ptr to the function by-pointer instead of by-value. Basically, you'll pass a "pointer-to-pointer" as parameter into the function, the pointer-to-pointer pointing to you loc_ptr. Inside the function, you dereference the arrays memoryaddress from the pointer-to-pointer to access the original array. Once you've created and filled the new array, put the memory address of the new array into the parameter passed by-pointer.

Edit: I whipped up a quick example of both ways, this is actually in C++, but I'm 99% sure, that the pointers work the same in C (sorry if it's a bit verbose). Note that the arrays aren't freed anywhere, so this would cause memory leaks (but you should get the idea of passing by-value vs. by-pointer):

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

The output is:

The name of the first location pointer by loc_ptr is now Padstow
-- Replacing array, name of the first location in old array is Padstow
The name of the first location pointer by loc_ptr is now Replacing pointer by return value
-- Modifying pointer, name of the first location pointed originally is Replacing pointer by return value
The name of the first location pointer by loc_ptr is now From modifyViaGivenPointerToPointer


How are you returning the new array from your function.

If you are going to change the address where the array resides, you will need a double pointer (pointer to pointer).

This won't work:

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


If you have:

struct location a;
struct location b;

a = b;

you will make a copy of the data in b into a.

You seem to be doing the following:

struct location *a;
struct location *b;

a = b;

This copies the pointer of b into a; not the data.

What you perhaps mean is:

*ptr = *new_ptr;

To copy the data pointed to by new_ptr into the location pointed to by ptr.


When you do

ptr = new_ptr;

I'm assuming that ptr is the parameter to your function. What you are actually doing is overriding the value on the stack (the value of the pointer itself), which will not change the value of the pointer outside the function. You can either pass back the new pointer, or take as an argument a double pointer to 'location', and then do:

*p_ptr = new_ptr;


If you want changes to the array to be reflected through the location variable, then you will need to modify that array directly, in place. If you'd rather make all your changes to a copy of the array, that is fine, but then you must loop through the entire array and copy all structs back to the first array.

Be very careful to keep the array lengths the same OR always maintain an array-length variable somewhere that NEVER GROWS. C arrays do not grow. You can try growing one with realloc(3), but it can fail, and the original must be allocated with malloc(3) in the first place. They can shrink, sort of, if you just pretend they are shorter... :)


I assume you're doing something on the order of

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

If so, the solution is

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

If you want to change the value of loc_ptr rather than what loc_ptr points to, you must pass a pointer to it to the function.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号