user5423
user5423

Reputation: 145

How to access a pointer struct's member variables?

I haven't programmed in C++ in a while, so I've been trying to improve. I have a very simple login function, however it doesn't work. The login function calls getUserAttempts() which returns a pointer to a struct that contains user details such as username and password. However, any time I try to access the pointer's struct's variables, the program crashes. I feel like I've missed something obvious but can't put my finger on it.

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

typedef std::unordered_map<std::string, std::string> unorderedMap;

typedef struct Credentials {
    std::string username;
    std::string password;
} structCred;

void login();
structCred* getUserAttempts();


void login() {  
    unorderedMap credentialMap;
    credentialMap["username"] = "mypassword123";
    structCred *p;

    for (int i = 0; i < 3; i++) {
        p = getUserAttempts();
        auto it = credentialMap.find(p->username);
        std::cout << it->first;
        std::cout << it->second;
    }
    return;
}


structCred *getUserAttempts() {
    structCred credentialAttempt;
    std::string username, password;
    std::cout << "Please enter your username: ";
    std::getline(std::cin, credentialAttempt.username);
    std::cout << "Please enter your password: ";
    std::getline(std::cin, credentialAttempt.password); 
    return &credentialAttempt;
}


int main() {
    std::cout << "Welcome..." << std::endl;
    login();
    return 0;
}

Upvotes: 0

Views: 84

Answers (2)

cigien
cigien

Reputation: 60288

In this function:

structCred *getUserAttempts() {
    structCred credentialAttempt;
    // ...
    return &credentialAttempt;
}

you are returning an address to a local variable which dies at the end of the function. Accessing the memory is then undefined behavior.

Instead, you should allocate memory for it:

structCred *getUserAttempts() {
    structCred *credentialAttempt = new structCred;
    // ...
    return credentialAttempt;
}

Note that statements like credentialAttempt.username will have to become credentialAttempt->username.

However, returning a raw pointer is usually a bad idea, since there is no way of knowing whose responsibility it is to free the memory. Instead, use a unique_ptr that will take care of freeing the memory for you:

std::unique_ptr<structCred> getUserAttempts() {
    auto credentialAttempt = make_unique<structCred>();
    // ...
    return credentialAttempt;
}

Upvotes: 2

cdhowie
cdhowie

Reputation: 169328

return &credentialAttempt;

This returns a pointer to the function-local variable credentialAttempt. That doesn't work because the function local is destroyed immediately when the function returns, so the function is returning a pointer to something that no longer exists. Dereferencing the returned pointer is therefore undefined behavior.

Instead, just return the object by value:

structCred getUserAttempts() {
    structCred credentialAttempt;
    std::string username, password;
    std::cout << "Please enter your username: ";
    std::getline(std::cin, credentialAttempt.username);
    std::cout << "Please enter your password: ";
    std::getline(std::cin, credentialAttempt.password); 
    return credentialAttempt;
}

Upvotes: 3

Related Questions