【问题标题】:Pointer of array of structure结构体数组的指针
【发布时间】:2014-01-06 10:29:08
【问题描述】:

好的,我有这个代码:

#include <stdio.h>
#include <stdlib.h>

#define ARR_SIZE 5

struct mys
{
    double first;
    unsigned long second;
    char str[10];
};

int main(int argc, char** argv)
{
    size_t i = 0;
    struct mys thes[ARR_SIZE] = 
        {
            {1.1, 1, "First"},
            {2.2, 2, "Second"},
            {3.3, 3, "Third"},
            {4.4, 4, "Fourth"},
            {5.5, 5, "Fifth"}
        };//load array of structures with values

    for (; i < ARR_SIZE; ++i)
        fprintf(stdout, "second->%lu\n", thes[i].second);//loop through array thes and print element second

    return (EXIT_SUCCESS);
}

现在,我想获取第零个元素 thes 的第二个元素的地址,然后使用它循环遍历数组 thes 并打印每个第二个元素。

#include <stdio.h>
#include <stdlib.h>

#define ARR_SIZE 5

struct mys
{
    double first;
    unsigned long second;
    char str[10];
};

int main(int argc, char** argv)
{
    size_t i = 0;
    unsigned long * ptr = NULL;//pointer to unsigned long
    struct mys thes[ARR_SIZE] = 
        {
            {1.1, 1, "First"},
            {2.2, 2, "Second"},
            {3.3, 3, "Third"},
            {4.4, 4, "Fourth"},
            {5.5, 5, "Fifth"}
        };

    //first loop
    for (; i < ARR_SIZE; ++i)
        fprintf(stdout, "second->%lu\n", thes[i].second);

    ptr = &thes[0].second;//get the address of the second element of the zero'th array structure and store it in ptr

    // Now I want to use the above pointer ptr to loop through the array thes and display the second element like I did above, but I can't manage to do that.
    //The output of this loop should be the same as the first loop 

    return (EXIT_SUCCESS);
}

所以,我已经实现了指针,但是在编写第二个循环的代码时遇到了问题。任何帮助表示赞赏。

【问题讨论】:

  • @itwasntpete 我的代码是 C :)

标签: c loops pointers struct


【解决方案1】:

你不能那样做。至少不简单。你的数组是结构。他们连续坐在记忆中。增加指针ptr 而不进行任何强制转换,会将其移动到内存块中的下一个long 地址,该地址不在下一个结构中,而是在它旁边。

【讨论】:

    【解决方案2】:

    您的要求没有多大意义:您所拥有的只是一个指向unsigned long 的指针,没有任何信息可以确定所讨论的数字是某些特定结构数组的一部分。

    可以做到这一点,使用指针技巧,但它肯定不是直截了当的或者我在一般编程中推荐的东西。

    为什么需要这样做?

    我会通过计算一个指向结构的指针来做到这一点,以使迭代更清晰:

    const struct mys *mysp = (struct mys *) ((char *) ptr -
                                             offsetof(struct mys, second));
    

    这使用offsetof 从指向结构成员的指针“备份”到结构本身。

    【讨论】:

    • 我只是想了解它是如何完成的,我没有计划在一般编程中使用它。
    【解决方案3】:
    for (; i < ARR_SIZE; ++i)
        fprintf(stdout, "second->%lu\n", *( unsigned long * )(( char * )ptr + i * sizeof( struct mys ) ));
    

    【讨论】:

    • @StoryTelle 而不是 unsigned long *ptr 你可以使用 struct mys *ptr = thes;并在打印语句中使用 ptr->second 然后简单地增加 ptr:++ptr。会更简单。
    • @VladfromMoscow,这也是建议的方法。某些过分热心的程序员肯定会阅读此 hack,他们会在某处使用它并打破时间和空间的结构。
    • @itwasntpete,弗拉德,这是我的想法,但你先发布了,所以从我这里拿走 10 个 :)
    【解决方案4】:

    你不能(或更重要的是不应该)那样做。你应该做的是保护指向数组第一个元素的指针,这样你就可以迭代它。

    struct mys* ptr;
    
    ptr = &thes[0];
    
    for(int i=0; i<10; i++, ptr++)
      fprintf(stdout, "second->%lu\n", ptr->second);
    

    但您必须小心,因为没有结束元素,并且 iteratig [0-10) 仅在以 ptr = &amp;thes[0]; 开头的情况下才正确。

    【讨论】:

      【解决方案5】:

      这是对 Vlad 解决方案的一点解释。这是用 c++ 编写的(在 for 循环中声明的变量):

      我们将ptr 转换为unsigned char*(字节指针),然后将其增加mys 占用的字节数,以将其设置为下一个元素的second。然后我们将其转换回ulong,并取消引用指针以获取其值。

      ptr = &thes[0].second; //get the address of the second element of the zero'th array structure and store it in ptr
      for (i = 0; i < ARR_SIZE; ++i)
      {
          unsigned char* pointer_as_byte = (unsigned char*)ptr; // get ptr as byte ptr to increment it
          unsigned char* pointer_offset = pointer_as_byte += (i * sizeof(struct mys)); // next structure's [second] field
          unsigned long* final_pointer = (unsigned long*)pointer_offset; // cast byte ptr back to ulong ptr
      
          fprintf(stdout, "second->%lu\n", *final_pointer);
      }
      

      或者换一种方式,也许更容易理解:

      ptr = &thes[0].second;//get the address of the second element of the zero'th array structure and store it in ptr
      for (i = 0; i < ARR_SIZE; ++i)
      {
          mys* pointer_as_mys = (mys*)ptr; // get ptr as mys pointer
          pointer_as_mys += i; // increment is to i'th mys.second
          ptr = (unsigned long*)pointer_as_mys; // cast it back to save the offset to ptr
      
          fprintf(stdout, "second->%lu\n", *ptr);
      }
      

      【讨论】:

        【解决方案6】:

        当然可以。不好,没用,但可以通过操作指针来完成。

        为了理解,看看你的结构数组在内存中的布局,假设你的数组从地址 0x0000 开始:

        0x0000 : array[0].first  - first part of mys.first
        0x0004 : array[0].first  - second part of mys.first
        0x0008 : array[0].second
        0x000c : array[0].str[0-3] - first four elements of your string
        0x0010 : array[0].str[4-7] - next four elements
        0x0014 : array[0].str[8-9] - last two elements and padding
        0x0018 : array[1].first  - second element !
        

        ...

        所以你可以看到在数组的两个连续元素的相同字段之间你有结构的大小。

        要遍历内存中几个连续结构的相同字段,您只需声明一个指向第一个结构元素的指针,并将其增加结构的大小,以访问下一个元素的相同字段数组。

        在你的情况下,它看起来像:

        int i;
        struct mys my_array[SIZE];
        char* my_iterator = &my_array[0].second;
        for(i=0; i<SIZE; i++) {
            fprintf(stdout, "second->%lu\n", *(unsigned long*)my_iterator);
            my_iterator += sizeof(mys);
        }
        

        但这确实不好看,你可以稍微改进一下,但在不需要的时候玩指针仍然不是一个好习惯。

        int i;
        struct mys my_array[SIZE];
        strut mys* my_iterator = &my_array[0].second;
        for(i=0; i<SIZE; i++, my_iterator++) {
            fprintf(stdout, "second->%lu\n", *(unsigned long*)my_iterator);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-03
          • 1970-01-01
          • 2013-02-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多