【问题标题】:Assigning struct array to pointer将结构数组分配给指针
【发布时间】:2011-06-18 02:14:55
【问题描述】:

我已经初始化了一个结构数组(只包含一个名为 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;
}    

但是,它不会更改原始数据。你能解释一下我在将这个新数组分配给我的原始指针时做错了什么吗?

【问题讨论】:

  • 请在您的问题中添加以下内容。你如何在函数中创建一个新数组?如何从函数返回创建的数组?如果您只是发布函数的代码,将所有不相关的代码替换为像// modify the array 这样的短 cmets,那就太好了。另外,您只提到了一次ptr,并且您没有解释它的来源。一开始你有loc_ptr

标签: c arrays pointers struct


【解决方案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 指向的值,则必须将指向它的指针传递给函数。

【讨论】:

    【解决方案2】:

    好久没做C语言了,有点生疏了,不过还是试试吧……

    我会看到(至少)有两种方法可以让它工作:或者从函数返回新数组的新指针并将其存储在旧指针中,类似于(这可能在语法上不正确):

    loc_ptr = someFunctionCreatingTheNewArrayAndReturningAPointerToIt(loc_ptr);

    另一种可能性是将 loc_ptr 按指针而不是按值传递给函数。基本上,您将“指针到指针”作为参数传递给函数,指针指向您的 loc_ptr。在函数内部,您从指向指针的指针中取消引用数组内存地址以访问原始数组。创建并填充新数组后,将新数组的内存地址放入指针传递的参数中。

    编辑:我为这两种方式做了一个简单的例子,这实际上是在 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 的第一个位置指针的名称现在是 From modifyViaGivenPointerToPointer

    【讨论】:

    • 在谈论 C 时,我不会说“通过引用”。有人可能会将其与 C++ 混淆。只需说“按指针”即可。
    【解决方案3】:

    如果您希望通过location 变量反映对数组的更改,那么您将需要直接修改该数组。如果您希望对数组的副本进行所有更改,那很好,但是您必须遍历整个数组并将所有结构复制回第一个数组。

    要非常小心地保持数组长度相同,或者总是在某个永远不会增长的地方维护一个数组长度变量。 C 数组不会增长。您可以尝试使用realloc(3) 增长一个,但它可能会失败,并且原始必须首先分配malloc(3)。他们可以缩小,有点,如果你只是假装他们更短...... :)

    【讨论】:

    • 函数正在移除一个元素;所以我的意图是假装它们变小了。
    【解决方案4】:

    当你这样做时

    ptr = new_ptr;
    

    我假设ptr 是您的函数的参数。您实际上所做的是覆盖堆栈上的值(指针本身的值),这不会更改函数外部指针的值。您可以将新指针传回,也可以将指向“位置”的双指针作为参数,然后执行以下操作:

    *p_ptr = new_ptr;
    

    【讨论】:

      【解决方案5】:

      如果你有:

      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指向的位置。

      【讨论】:

      • 但请注意,C 没有通过单个赋值复制 数组 事物的机制。
      • 啊,是的,完全正确。这只会复制一个元素,而不是数组。
      【解决方案6】:

      您如何从函数中返回新数组

      如果您要更改数组所在的地址,则需要一个双指针(指向指针的指针)。

      这行不通:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-08
        • 1970-01-01
        • 2015-10-26
        • 2019-06-26
        • 2018-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多