how to return an array of struct pointers?

102 views Asked by At

i want to return an array of struct pointers.

i want the array of struct pointers became accessible in the main function. but it always breaks. i have tried using smart pointers but it seems like they don't do well with arrays or something. can someone tell me what step should i take to fix this problem?

sorry if the variable is written in Indonesian.

#include <iostream>

struct dataPasien {
    int id;
    int umur;
    std::string nama;
    std::string penyakit;
};

void daftarMenu() {
    std::cout << "1. " << std::endl;
    std::cout << "2. " << std::endl;
    std::cout << "3. " << std::endl;
    std::cout << "4. " << std::endl;
}

dataPasien* input() {
    dataPasien* arr = new dataPasien[100];

    int jumlah;
    std::cout << "berapa pasien? ";
    std::cin >> jumlah;

    for(int i = 0; i < jumlah; i++) {
        arr[i].id = i + 1;

        std::cin.ignore();
        std::cout << "nama? ";
        getline(std::cin, arr[i].nama);

        std::cout << "umur? ";
        std::cin >> arr[i].umur;

        std::cin.ignore();
        std::cout << "penyakit? ";
        getline(std::cin, arr[i].penyakit);
    };

    return arr;
}
    
int main() {
    int menu = 0;
    std::cout << "apa ?";
    std::cin >> menu;

    switch(menu) {
        case 1: {
                    dataPasien* arr = input();
                }break;
        case 2: 
                std::cout << "it breaks";
        case 3:
                break;
        case 4:
                break;
        default:
                break;
    }

    std::cout << "it just breaks" ;
    dataPasien* arr = arr;
    for(int i = 0; i < 2;i++) {
        std::cout << "id : " << arr[i].id << std::endl;
        std::cout << "nama : " << arr[i].nama << std::endl;
        std::cout << "umur : " << arr[i].umur << std::endl;
        std::cout << "penyakit : " << arr[i].penyakit << std::endl;
    }
    return 0;
}

i have tried smart pointers but it seems like they don't do well with arrays. i've tried many things but it always ended with memory leaks

3

There are 3 answers

0
Pepijn Kramer On

Rewrite your code to return a std::vector like this. (I see I should not have changed the getlines if you want to have a name contain white spaces)

std::vector<dataPasien> input() 
{
    std::vector<dataPasien> arr;
    dataPasien new_data;

    int jumlah;
    std::cout << "berapa pasien? ";
    std::cin >> jumlah;

    for(int i = 0; i < jumlah; i++) 
    {
        std::cout << "nama? ";
        std::cin >> new_data.nama;

        std::cout << "umur? ";
        std::cin >> new_data.umur;

        std::cout << "penyakit? ";
        std::cin >> new_data.penyakit;

        arr.push_back(new_data);
    };

    return arr;
}
0
tbxfreeware On

how to return an array of struct pointers?

The program in the OP uses operator new[] to allocate an array of structs. The problem is how to return that array to the calling routine. As with all built-in arrays, it is necessary to store both a pointer to the array elements, and the size of the array.

  • arr – pointer to array elements, where each element is a struct
  • jumlah – the number of elements in the array, i.e., the array size

The following program is a simplified version of the program in the OP. It omits the menu, which is not essential to the question at hand. The biggest change, however, is that the number of patients, jumlah, is input in function main, rather than inside function input. Thus, arr and jumlah are both available in function main.

The program in the OP contains a subtle bug regarding function cin.ignore. In function input, the first pass through the loop works fine, but all subsequent passes call function cin.ignore at the top of the loop, even though the preceding input was made using getline (and the end of the preceding iteration). That error has been corrected by placing calls to cin.ignore immediately after the cin >> value expressions that leave a newline on the input stream.

Comments in function main describe the other changes made to the original program.

At the end of this answer, a solution using std::vector is presented. If the OP is allowed to use std::vector, that is the best way to go. It may be, however, that built-in arrays are part of the problem spec, which is why I present the following demonstration program first.

Demonstration program

// main.cpp
#include <cstddef>
#include <iostream>
#include <string>

struct dataPasien {
    int id;
    int umur;
    std::string nama;
    std::string penyakit;
};

dataPasien* input(std::size_t const jumlah)
{
    std::cout << "INPUT PATIENT DATA\n\n";
    auto arr = new dataPasien[jumlah]{};
    for (int i = 0; i < jumlah; i++) {
        arr[i].id = i + 1;

        std::cout << "nama? ";
        std::getline(std::cin, arr[i].nama);

        std::cout << "umur? ";
        std::cin >> arr[i].umur;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

        std::cout << "penyakit? ";
        getline(std::cin, arr[i].penyakit);

        std::cout << '\n';
    }
    return arr;
}
void display_patient_data(dataPasien const* arr, std::size_t const jumlah)
{
    std::cout << "PATIENT DATA\n\n";
    for (std::size_t i = 0; i < jumlah; ++i) {
        std::cout 
            << "id : " << arr[i].id 
            << '\n' << "nama : " << arr[i].nama 
            << '\n' << "umur : " << arr[i].umur 
            << '\n' << "penyakit : " << arr[i].penyakit 
            << "\n\n";
    }
}
int main()
{
    // Get the number of patients BEFORE calling function `input`.
    std::size_t jumlah;
    std::cout << "berapa pasien? ";
    std::cin >> jumlah;
    std::cout << '\n';

    // This is the proper way to discard the rest of a line, 
    // including the newline character that ends it.
    // See: https://en.cppreference.com/w/cpp/io/basic_istream/ignore
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    // Variable `arr` is an "owning" pointer. Operator `delete[]` 
    // will be called on this pointer at the end of function `main`.
    auto arr = input(jumlah);

    // Now that we have both the array and its size, we can 
    // use them in function `main`, and/or pass them to other 
    // functions.
    display_patient_data(arr, jumlah);

    // Get in the habit of calling operator `delete[]` for every 
    // array that is allocated using operator `new[]`. Otherwise, 
    // your programs will leak memory.
    delete[] arr;
    return 0;
}
// end file: main.cpp

Sample output

berapa pasien? 2

INPUT PATIENT DATA

nama? Joe Dokes
umur? 42
penyakit? marriage

nama? Mary Moneypenny
umur? 35
penyakit? vanity

PATIENT DATA

id : 1
nama : Joe Dokes
umur : 42
penyakit : marriage

id : 2
nama : Mary Moneypenny
umur : 35
penyakit : vanity

Solution with std::vector

Using a vector avoids the error-prone coding that goes along with new and delete. In addition, a vector carries its size with it, so there is no need to keep track of that separately.

This is the same program as above, but modified to use std::vector. It inputs the number of patients, jumlah, at the top of function input, rather that in function main.

// main.cpp

#include <cstddef>
#include <iostream>
#include <string>
#include <vector>

struct dataPasien {
    int id;
    int umur;
    std::string nama;
    std::string penyakit;
};

std::vector<dataPasien> input()
{
    std::cout << "INPUT PATIENT DATA\n\n";
    std::size_t jumlah;
    std::cout << "berapa pasien? ";
    std::cin >> jumlah;
    std::cout << '\n';

    // This is the proper way to discard the rest of a line, 
    // including the newline character that ends it.
    // See: https://en.cppreference.com/w/cpp/io/basic_istream/ignore
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    std::vector<dataPasien> arr(jumlah);
    for (int i = 0; i < jumlah; i++) {
        arr[i].id = i + 1;

        std::cout << "nama? ";
        std::getline(std::cin, arr[i].nama);

        std::cout << "umur? ";
        std::cin >> arr[i].umur;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

        std::cout << "penyakit? ";
        getline(std::cin, arr[i].penyakit);

        std::cout << '\n';
    }
    return arr;
}
void display_patient_data(std::vector<dataPasien> arr)
{
    std::cout << "PATIENT DATA\n\n";
    for (auto const& p : arr) {
        std::cout
            << "id : " << p.id
            << '\n' << "nama : " << p.nama
            << '\n' << "umur : " << p.umur
            << '\n' << "penyakit : " << p.penyakit
            << "\n\n";
    }
}
int main()
{
    auto arr = input();
    display_patient_data(arr);
    return 0;
}
// end file: main.cpp
0
artichoke On

You have a problem but that is not related to what you ask.

You initialize a variable with indetermined value and then try to access that indetermined value.

dataPasien* arr = arr; // its legal. but causes error. assigned `arr` is not arr in switch statement

You can just define dataPasien* before switch statement, assign in switch statement and after use safely.