0

I am teaching myself C++ and am working through exercises in a tutorial book. In the current problem, I am supposed to pass in a null pointer to a method for the last name parameter that triggers a prompt for assigning the last name.

My problem is that this either:

  1. Throws an exception.
  2. Does not carry back outside of the method if I assign in ways to avoid the exception.
  3. Seems to require a double pointer or reference, based on my current search findings. However, I need to use a pointer parameter for the method (I use a reference parameter as another exercise), and double pointers are not introduced yet in the text (so I feel like this is cheating/missing the point of the lesson).

How do I assign to a string null pointer such that it is preserved outside of the method without using references or double pointers?

Current code:

#include <iostream>
#include <string>

using namespace std;

void getNameByPointer(string* firstName, string* lastName)
{
    cout << "Please enter your first name: ";
    cin >> *firstName;

    // Check for null. 
    // Only request last name IF null, as per the book exercise statement.
    if (!lastName) 
    {
        string tempLastName;
        cout << "Please enter your last name: ";
        cin >> tempLastName;

        // Note: All assignment methods below fail in some way if lastName is null. 
        // I cannot find a way to assign to a null pointer that carries out 
        // of the method without using a double pointer or pointer 
        // reference, which are not yet introduced in the book.

        // (1) Throws exception 'Read Access violations': std::_String_alloc<std::_String_base_types<char,std::allocator<char> > >::_Myres(...) returned 0x18.
        // *lastName = tempLastName;    

        // (2) This assignment is limited to the method scope.
        // lastName = &tempLastName;

        // (3) This assignment is limited to the method scope.
        // lastName = new string(tempLastName);     
    }
}

int main()
{
    string firstName;
    string lastName;

    getNameByPointer(&firstName, &lastName);
    cout << "Your name is " << firstName << " " << lastName << '\n';

    cout << "Calling method with NULL...\n";
    string firstName1;
    // Null pointer
    string *lastName1 = nullptr;

    getNameByPointer(&firstName1, lastName1);
    if(lastName1)
    {
        cout << "Your name is " << firstName1 << " " << *lastName1 << '\n';
    }
    else
    {
        cout << "Your name is " << firstName1 << '\n';
    }
}

Edit: To better clarify if I have misread the problem, or better communicate my restraints, the problem is stated below:

Exercise 3

Modify the program you wrote for exercise 1 so that instead of always prompting the user for a last name, it does so only if the caller passes in a NULL pointer for the last name.

(Exercise 1 has already been solved but is the basis for Exercise 3.)

Exercise 1

Write a function that prompts the user to enter his or her first name and last name, as two separate values. This function should return both values to the caller via additional pointer (or reference) parameters that are passed to the function. Try doing this first with pointers and then with references.

(For Exercise 3, a similar solution was done for the reference function by just checking if the variable is empty as NULL cannot be checked for in the reference parameter.)

8
  • 2
    Are you sure you want to use pointers? You can pass the strings by reference and if they are empty you can check that with empty(). Commented Aug 2, 2017 at 18:21
  • I already pass by reference as another part of the exercise. So my question is on implementation rather than strategy. Or perhaps what they are asking for in the exercise is technically not doable due to variable scope issues? Commented Aug 2, 2017 at 18:26
  • 1
    Are you allowed to accept a reference to the pointer? Like: void getNameByPointer(string* firstName, string*& lastName) ? Commented Aug 2, 2017 at 18:33
  • 1
    Use separate functions. Rule of thumb is that if you have an "optional" parameter that completely cuts off half the functions processing, the function is doing too much. Commented Aug 2, 2017 at 19:29
  • 1
    Show us the full text of the exercise. Maybe you are missing something. Or we can show you a better way to solve it. Commented Aug 2, 2017 at 19:32

2 Answers 2

2

EDIT: I believe it is all aboout mistake in excercise 3, where it should be "not-NULL" instead of NULL pointer case, but it is not an proper answer, so let's analyze given case and see if it leads to contradiction.

So we have to return value when we give a function a nullptr. Since pointer's value is null it carries no information which object's value should function modify. There are only workarounds, like in your 3rd point, but it's not changing the answer to: "How do I assign to a string null pointer such that it is preserved outside of the method without using references or double pointers?" - you simply can't, since only information that nullpointer carries it that it is null. Nothing about caller scope, so it cannot modify it.

OLD: Your problem is in if statement:

    // Check for null
    if (!lastName || lastName->empty()) 

Try with

    if (lastName) 

!lastName makes it go into if it is equal nullptr. You don't have to check if it is empty (unless you don't want to override current string). What is more, if it is nullptr you cannot call its member function (although in here it does not get called, because it is not evaluated, since !lastName is true).

Rest of the code works fine, so it's not about null pointer passing :)

Sign up to request clarification or add additional context in comments.

9 Comments

!lastName || lastName->empty() underlies the rules of short-circuit evaluation, so if !lastName is true, lastName->empty() will never be executed; if lastName is a null pointer, it will not be dereferenced. Besides, this does not answer the question. The OP has an exercise to solve and he is having trouble doing so. Passing a null pointer is required by the exercise.
@Downvoter - The inverted condition is the problem. And if (lastName) is the solution.
@StoryTeller There are three options in the code, all commented out because none work. The OP is seeking an alternative doing the equivalent thing and that is the question in my eyes. This answer might solve something but not the question. if (lastName) would prompt the user if lastName was already initialized with a non-null pointer and that is definitely not what the OP wants.
@Downvoter - The first does not work because the OP slips in a nullptr. Recall that lastName is string*, and not string. I.e. that's why *lastName = tempLastName; crashes, the UB. Those are C-style output parameters. Of course the OP wants to write into the pointed to objects only if the pointers are pointing at valid objects.
@StoryTeller This answer says "if it is nullptr you cannot call its member function." I assume the member function call here is lastname->empty(). It won't be called upon a null pointer, though, because of short-circuit evaluation, that's what I want to say. The answer even mentions that, contradicting itself ("you cannot call its member function [...] although in here it does not get called". Changing it to if (lastName) ignores the exercise because it asks the user for a surname if the argument is not null; exercise 3 requires the exact opposite, so this is wrong to begin with.
|
1

I think the problem here is a misunderstanding of exercise 1 leading to a problem with exercise 3. I believe from the provided text that it is poorly worded exercise and hence the confusion. Here is one possible solution to exercise one.

#include <string>
#include <iostream>

void ExerciseOne(std::string *, std::string *, std::string *);

int main(){

    std::string first, second, result;

    ExerciseOne(&first, &second, &result);

    return 0;
}

void ExerciseOne(std::string *first, std::string *last, std::string *result){
    std::string temp;
    std::cout << "What is your first name?\n";
    std::getline(std::cin, temp);
    *first = temp;
    std::cout << "What is your last name?\n";
    std::getline(std::cin, temp);
    *last = temp;
    *result = *first + ' ' + *last;
    return;
}

Note this statement:

This function should return both values to the caller via additional pointer (or reference) parameters that are passed to the function.

Why would we need additional parameters? I can only assume that this means there should be more inputs than simply the first and last names. Without seeing the complete text I can't be sure. Perhaps the point is to show that pointers (and references) can be used as both inputs and outputs. Exercise 3 follows by simply checking that one of the pointers is valid.

void ExerciseThree(std::string *first, std::string *last, std::string *result){
    *result = *first + ' ';
    if (last == NULL){
        std::string temp;
        std::cout << "What is your last name?\n";
        std::getline(std::cin, temp);
        *result += temp;
    }
    else {
        *result += *last;
    }
    return;
}

As you saw in your tests you cannot assign a local string to the pointers and have it remain valid outside your function. Without more input parameters the exercise doesn't make alot of sense. Of course you can make the function simply return a string and avoid the third parameter entirely.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.