Pointers Question

This piece of code is supposed to run a function do_file on some text documents, and store the results from each as a new array. Then I want it to go through and output the values of each array:

1
2
3
4
5
6
7
8
double bru1003=do_file("old_data/1003b.txt");
double bru0407=do_file("old_data/0407b.txt");

ofstream printer;
printer.open ("file.txt");
    for(int k=2;k<master_num_total;k++){
        printer<<master_name_list[k]<<"\t"<<bru1003[k]<<"\t"<<bru0407[k]<<"\n";
    }


Unfortunately, do_file is returns a double* (because it doesn't seem to work any other way). As is, the compiler tells me I can't convert double* to double on initialization. I don't really understand pointers- this seemed easier in Java.

Can anyone please help me?
Assuming there aren't any other issues, then simply changing it double to double* should make it work. The do_file() function looks like it is returning an array of doubles (your access method on line 7 leads me to believe this), so storing it in a pointer is probably what you want to do. The only thing I'd mention is that it would probably need to be a dynamically allocated array, which you would then need to free yourself...ugh.
When I store them as double*s, the program compiles, but I get a problem.

It seems as if its calculating do_file for both arrays, but then printing the values of the array I declare second (bru0407) for both of them.So when it finally gets around to printing, I get two columns of the same data (that of the array I declare second).

I thought this might have something to do with the way pointers work (I thought it might be pointing to the same place). Is this possible?
"I thought this might have something to do with the way pointers work (I thought it might be pointing to the same place). Is this possible?"

It's certainly possible; it depends on how the insides of do_file works. Given that it's returning a pointer, possibly the innards of do_file uses the same piece of memory every time.

You can find out for sure, though, by outputting your bru1003 contents immediately after line 1.

If it turns out that this is the case, and that do_file uses the same piece of memory each time, there are lots of things you can do about it; the first one that jumps to mind is something like this (untested, just written off the top of my head to give you the idea):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <vector>

double bru1003=do_file("old_data/1003b.txt");

std::vector<double> vecbru1003;
vecbru1003.reserve(10); // reserve some space
for(int k=2;k<master_num_total;k++){
      vecbru1003[k] = bru1003[k] ;
    }

double bru0407=do_file("old_data/0407b.txt");

std::vector<double> vecbru0407;
vecbru0407.reserve(10); // reserve some space
for(int k=2;k<master_num_total;k++){
      vecbru0407[k] = bru0407[k] ;
    }

ofstream printer;
printer.open ("file.txt");
    for(int k=2;k<master_num_total;k++){
        printer<<master_name_list[k]<<"\t"<<vecbru1003[k]<<"\t"<<vecbru0407[k]<<"\n";
    }


This will store the values you're interested in, in a std::vector that you control. Given that do_file returns a pointer, it's presumably allocating memory somewhere. Just out of interest, is there some function a bit later in the code that deallocates that memory?
Last edited on
While I'm here, pointers are a lot easier than many think, but they're often taught using clumsy analogies, which frankly are unhelpful.

A pointer type is a basic type, just like any other (e.g. int, double, char). You create one and it exists somewhere in memory.

int*, char*, double*.... they all take up the same space in memory and essentially they are just a number. Ignore for the moment that they are int pointers or char pointers or double pointers. In memory, they all look the same.

1
2
3
4
5
int* p_x; // You have now created a space in memory the size of a pointer.
               //  It's often the same size as an int. Right now, if you look at that memory that
               // effectively is p_x, it'll have some garbage value in it.
p_x = 0 ; // Now, if you look in that piece of memory, it'll have the number 0 in it.
p_x = 3425 ; // Now,  if you look in that piece of memory, it'll have the number 3425 in it. 


Note that in none of the above steps did you actually create a new int; you have not made an int, you have made an int*.

1
2
3
4
int y = 12; // Now we HAVE made an int somewhere in memory, with the value 12
                  // If only we knew its address in memory, we could put that address value in p_x
p_x = &y;   //  The '&' operator here returns the memory address of y, so now the value of p_x
                  //   is the address of y 


There is an operation you can carry out on a pointer called "dereferencing". This operation reaches the contents of an address in memory. The address is just a number; the number used for the address is the value of the pointer.

1
2
*p_x; // Returns (and in this case doesn't do anything with) the contents of memory address &y
          //  which in this case we know to be the number 12 


But wait, you cry. There could be anything in that memory. Anything at all. How does the compiler know how to treat it? Good question. It knows because you explained when you created p_x what kind of things it would point at. We made an int pointer, so the value returned will be treated as an int.

1
2
3
4
int z = *p_x;  // Z is now whatever value was at memory address &y, interpreted as an int
                     //   So now we've got three objects in memory (two integers, y and z, and an 
                    //    int pointer, p_x
                     //  z is 12, y is 12, and p_x is a number that is the address of y in memory 


If you try something like this:

 
double z = *p_z;


the compiler should warn that you're trying to assign an integer value to a double; it may carry out some kind of conversion for you, it may just refuse outright, depending on your setup. There are some special values of pointer; if your pointer has a value of 0, it is a null pointer and deliberately does not point anywhere. This is also known as a NULL pointer.

If you understand pointers like this, by actually knowing what they do in terms of the memory, they become an absolute walk in the park. Pointer arithmetic and the relationship between pointers and array follow quite easily if you recall that a pointer is just the number of some other piece of memory somewhere.


First of all, Moschops, thank you for all of this help. That is the best explanation of pointers I've ever read, and I am beginning to understand what they do. I've never had any formal C++ training, I've been trying to learn what I need online; its great that there are such helpful people on the internet.

I still can't get this program of mine to work, though. I'm not sure I understand your vector space reserving method up there, but the compiler still tells me I can't convert a double* to a double for this line:

double bru1003=do_file("old_data/1003b.txt");

I still think the problem is that my do_file is working on the same piece of memory. When I list them sequentially (as you suggested above), it works perfectly:

1
2
3
4
5
6
7
8
9
double* bru1003=do_file("old_data/1003b.txt");
for(int j=2;j<master_num_total;j++){
        cout<<master_name_list[j]<<bru1003[j]<<"\n";
    }

double* bru0407=do_file("old_data/0407b.txt");
for(int j=2;j<master_num_total;j++){
        cout<<master_name_list[j]<<bru0407[j]<<"\n";
    }


But after second do_file function runs, it re-writes all the values of the first array, so I can't output them side by side in a text file. Is there any way I can store the results of my do_file function in a new array?
Last edited on
do_file returns a 'pointer to a double'. You have made bru1003 a 'double'. You cannot assign a 'pointer to a double' to a 'double'. They are different types. That was my code that was wrong; I didn't test it.

If you have a double value, you must put a double in it, or something that the compiler knows how to turn into a double. The compiler cannot turn a 'pointer to a double' into a 'double' for you. When you do this:

double* bru1003=do_file("old_data/1003b.txt");

you are creating a 'pointer to a double' and then making that 'pointer to a double' equal to whatever is returned by do_file. You can then store all those values yourself somewhere. In my first code, I was storing them in a std::vector object, which takes care of memory handling for you, and is safe. There is a simpler but more dangerous way, in which you manage the memory yourself like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
double* p_tempStorageArray = new int[NUMBER_OF_DOUBLE_VALUES_YOU_WISH_TO_STORE];
// Now p_tempStorageArray is a pointer, that points to some memory that has been allocated for you.

// How big is a double, in bytes?
int sizeOfADouble = sizeof(double);

// So how big is the array we want to copy?
int numberOfBytesToCopy = sizeOfADouble * NUMBER_OF_DOUBLE_VALUES_YOU_WISH_TO_STORE;
// If you get this wrong, you can copy information that you never meant to read, and write 
//  it all over memory that doesn't belong to you. This will cause a segfault if you're lucky.
//  If you're unlucky, if will trash your data and you won't notice until much later, and then
// you'll have no idea where the bug is.

// Now lets do a copy of the memory
memcpy(p_tempStorageArray, bru1003, numberOfBytesToCopy);

// Now we have p_tempStorageArray, a pointer to an array of doubles
//  which contains the same information as the array that bru1003 points to.
//  Thus, when the array that  bru1003 points to gets overwritten the next
//  time we use d0_file, we'll still have this copy.

// So now, at the end when it's time to write everything out, don't print out bru1003, print out p_tempStorageArray like this

printer.open ("file.txt");
    for(int k=2;k<master_num_total;k++){
        printer<<master_name_list[k]<<"\t"<<p_tempStorageArray[k]<<"\t"<<bru0407[k]<<"\n";

// You allocated some memory; don't forget to deallocate it
delete[] p_tempStorageArray


Be aware that allocating memory yourself and counting arrays and this sort of thing is simple, but dangerous. If you use proper C++ containers, you remove much of the danger, but you do have to understand a bit more C++.
Last edited on
Allocating memory sounds dangerous:
This will cause a segfault if you're lucky.


Instead, I went back and figured out how your vector method worked. Originally, it wasn't working because I hadn't allocated a big enough vector to fit my array. Instead of a 10 sized vector, it now fits all 800 of my doubles.

It works perfectly now. Thanks for all your help, Moschops. This experience has taught me a lot more about how this works.
Topic archived. No new replies allowed.