views:

75

answers:

4

I'm trying to get better at using pointers, and not using array notation. So I have a function to read user input and return a pointer to that array. I can do it like this and it seems to work ok:

float *GetValues(float *p, size_t n) 
{   

    float input;
    int i = 0;

    if ((newPtr = (float *)malloc(n * sizeof(float))) == NULL) {
        cout << "Not enough memory\n";
        exit(EXIT_FAILURE);
    }
    cout << "Enter " << n << " float values separated by whitespace: \n";

    while (scanf("%f", &input) == 1) {
        p[i] = input;
        i++;
        cout << *p;
    }
    return p;
}

But then if I do this:

float *GetValues(float *p, size_t n) 
{   
    float *newPtr;
    float input;

    if ((newPtr = (float *)malloc(n * sizeof(float))) == NULL) {
        cout << "Not enough memory\n";
        exit(EXIT_FAILURE);
    }
    cout << "Enter " << n << " float values separated by whitespace: \n";

    while (scanf("%f", &input) == 1) {
            *newPtr++ = input;
    }
    return newPtr;
}

I get just 0s entered into p. Why is that?

Also, do I have to allocate memory here for an array of size n? I first tried it with the method above using pointers and not allocating memory but just set p = to input and I was getting garbage values. Thanks!

Edited: Sorry, I allocated a new ptr and was returning the wrong one like you said. I was just trying to input the numbers into my pointer and display it back on the screen to myself and wasn't paying attention to the return type and I was getting an output of 0 when I would cout << *newPtr.

A: 

Um, p = newPtr;?

bmargulies
The OP is clearly inexperienced on the use of pointers so a fuller explanation might be appreciated
zebrabox
@zebrabox The code is so wrong that I don't know where to start to try to give a 'fuller explanation'. So I'm sticking with the basic fact of the problem, and waiting to see if the OP ever returns.
bmargulies
+2  A: 

Seeing as this is C++, have you considered:

void GetValues(std::vector<float> &values) 
{   
    float input;
    while (scanf("%f", &input) == 1) {
        values.push_back(input);
    }
}

And there's something called iostream classes that you can use instead of scanf. You should check it out!

Daniel Earwicker
I have not since we haven't been exposed to vectors yet.
Crystal
It sounds like you are being taught C, not C++. This is a form of cruelty rarely practised these days.
Daniel Earwicker
And much too often practiced. But it's teaching C++ as if it were C, rather than just teaching C, that's the problem.
Roger Pate
A: 

You don't even store any values in p. And you are returning the pointer that you pass as argument, which is not necessary. A better version would be:

long GetValues(float *p, size_t max) 
{   
    float input;
    long i;

    cout << "Enter at the most " << max << " float values separated by whitespace: \n";

    for(i = 0; i < max && scanf("%f", &input) == 1; ++i)
    {
        p[i] = input;
    }

    // Return the number of parsed numbers
    return i;
}
AndiDog
A: 

A few tips:


The first GetValues allocates newPtr (which is not declared within the function, a global variable?) but then does nothing with it. There are two possible ways that your function could work with regards to memory storage:

  1. The function gets a pointer to valid memory for an array of size large enough. In that case the signature of the function ought to be

    float *GetValues(float *array, size_t arraySize)

    to more clearly state the nature of the arguments. You need not to allocate anything inside the function.

  2. The function should allocate the needed memory itself and let the caller free the memory some time later. In that case you MUST have some kind of hint in the name of the function that it allocates memory. Otherwise you are in for a disaster in terms of maintaining this code because it will be extremely easy to make mistakes in freeing memory. You will not need to pass an array pointer to the function, but if you do it needs to be a double pointer for it to be of any meaning (C and C++ passes arguments by value so it is not possible to change a pointer which is passed as an argument)

    float *GetValuesAndAllocateMemmory(size_t n)

    float *GetValuesAndAllocateMemmory(float **array_pp, size_t n)


The loop in the second GetValues should be

float *start_p = p;
...
while (scanf("%f", &input) == 1) {
        *p++ = input;
        cout << *start_p;
}
return start_p;

in order to be identical to the first GetValues.


Here there is upper limit of number of float values is n but your code does not check this

cout << "Enter " << n << " float values separated by whitespace: \n";
while (scanf("%f", &input) == 1) {

and will crash if more than n floats are entered. Never trust user input data, even when it comes from yourself. Always verify. Search for the term "input validation" for more information about this.

cout << "Enter " << n << " float values separated by whitespace: \n";
entered_values = 0;
while (entered_values < n && scanf("%f", &input) == 1) {
       entered_values++;
hlovdal
Why do you declare start_p = p?
Crystal
The `start_p` variable is to remember the start of the array. At the end of the function the `p` variable will point to the last element since it has been incremented every time in the loop.
hlovdal
But by setting the two pointers, aren't they pointing to the same thing so start_p gets moved as well?
Crystal
No, `start_p` and `p` are two independent variables and `start_p` will remain pointing to the start independently of what `p` is pointing to.
hlovdal