Home > Enterprise >  Iterate over struct pointer
Iterate over struct pointer

Time:08-27

Given a struct pointer to the function. How can I iterate over the elements and do not get a segfault? I am now getting a segfault after printing 2 of my elements. Thanks in advance

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

using namespace std; 

struct something{
    
    int a;
    string b;
};

void printSomething(something* xd){
    while(xd){
    cout<<xd->a<<"  "<<xd->b<<endl;
    xd  ;
    }
}
int main()
{
    something m[2];
    m[0].a = 3;
    m[0].b = "xdxd";
    m[1].a = 5;
    m[1].b = "abcc";
    printSomething(m);

    return 0;
}

CodePudding user response:

You'll have to pass the length of the array of struct

void printSomething(something* xd, size_t n){
                                  //^^^^^^^^ new argument  printSomething(m, 2);
    size_t i = 0;
    while(i < n){ // while(xd) cannot check the validity of the xd pointer
    cout<<xd->a<<"  "<<xd->b<<endl;
    xd  ;
    i  ;
    }
}

You should better use std::vector<something> in C

CodePudding user response:

The problem is that you are assuming there is a nullptr value at the end of the array but this is not the case.

You define a something m[2], then

  • you take the address of the first element, pointing to m[0]
  • you increase it once and you obtain address to m[1], which is valid
  • you increase it again, adding sizeof(something) to the pointer and now you point somewhere outside the array, which leads to undefined behavior

The easiest solution is to use a data structure already ready for this, eg std::vector<something>:

std::vector<something> m;
m.emplace_back(3, "xdxd");
m.emplace_back(5, "foo");

for (const auto& element : m)
  ...

CodePudding user response:

When you pass a pointer to the function, the function doesn't know where the array stops. After the array has decayed into a pointer to the first element in the array, the size information is lost. xd ; will eventually run out of bounds and reading out of bounds makes your program have undefined behavior.

You could take the array by reference instead:

template <size_t N>
void printSomething(const something (&xd)[N]) {
    for (auto& s : xd) {
        std::cout << s.a << "  " << s.b << '\n';
    }
}

Now xd is not a something* but a const reference to m in main and N is deduced to be 2.

If you only want to accept arrays of a certain size, you can make it like that too:

constexpr size_t number_of_somethings = 2;
void printSomething(const something (&xd)[number_of_somethings]) {
    for (auto& s : xd) {
        std::cout << s.a << "  " << s.b << '\n';
    }
}

int main() {
    something m[number_of_somethings];
    // ...
    printSomething(m);
}

Another alternative is to pass the size information to the function:

void printSomething(const something* xd, size_t elems) {
    for(size_t i = 0; i < elems;   i) {
        std::cout << xd[i].a << "  " << xd[i].b << '\n';
    }
}

and call it like this instead:

printSomething(m, std::size(m));

Note: I made all versions const something since you are not supposed to change the element in the `printSomething´ function.

  •  Tags:  
  • c
  • Related