Questions about C++, pointers, OS and compiler memory allocation

  • #1
fluidistic
Gold Member
3,923
261
Sorry I don't have the codes right now.

In C plus plus, when I declare an int, but don't assign any value to it, a space in memory is allocated for it. I can define a pointer and check its adress in hexadecimal, so far so good. I can run this program over and over and usually the int is allocated nearly at the same spot in memory,(I am guessing in the RAM). I made some plots, and sometimes it can vary greatly but overall the values don't differ that much, it's a ''big'' number like 194344563 or something like that. As far as I understand, this number heavily depends on the OS and compiler, so if I could save those addresses in memory, I could possibly determine the OS and or compiler on which the program is running.

Now here's the thing. If I use a loop to allocate (freeing or not memory won't change the following behavior), the first value is as usual, i.e. the big int, but.then the next values are completely different. Sometimes I get 0's, other times negative ints. So the behavior is totally different than if I had ran the program N times. I couldn't find a way to create a single Cpp program that would be equivalent.to execute N times the simple cpp code. ChatGPT was also at a loss.

Now here's another strange.thing. If I allocate an array of dimension N of ints instead of a single int, then the 1st entry of this.array is the usual big int, but then some other values are 0's (usually the 3rd to 6th values might be 0's but not always), and this kills me.

How is that possible that several ints are allocated at the 0 memory entry? Why 0? And much more importantly, how can several ints fit in the same memory spot? That doesn't make any sense?
 
Technology news on Phys.org
  • #2
C++:
#include <iostream>
#include <thread>
#include <cstdio> // Include for printf
#include <cstdlib>
#include <sstream>
#include <string>
#include "int_and_pointer.h"

long int generate_int_and_pointer() {
// Allocate memory for an integer
int* x = new int [1];
std::cout << x << ": memory address of x in hexadecimal.\n";
// Deallocate the allocated memory
    //  if (i % 2 == 0) {
    //   delete x;
    //  }
    printf("%ld : Address in memory (decimal)\n", reinterpret_cast<long>(x));
std::cout << "Value at memory location " << x << ": " << *x << std::endl;

return reinterpret_cast<long>(x);
}

long int* save_addresses(int n) {
    long int* addresses_array = new long int[n];
for (int i=0; i< n; i++) {
  addresses_array[i] = generate_int_and_pointer();
}

return addresses_array;
}
 
  • #3
If "new" returns 0, it probably means that the allocation failed, and no memory was allocated.
 
  • #4
HrvojeDjurdjevic said:
If "new" returns 0, it probably means that the allocation failed, and no memory was allocated.
Why? According to stack overflow it should return std::bad_alloc in that particular case, not 0.
0 would mean ''success'', or not, if anything?
 
  • #5
Perhaps it will help understanding your code and question if you include what the program outputs?
It will also be helpful to know what platform you are on, what compiler you use. Note that "long int" (a.k.a. just "long") can be 32 or more depending on the architecture, so perhaps print out "sizeof(long)" as well (you are converting a pointer address to a long so if a long is 32 bit but address is 64 you throwing away something.
 
  • #6
fluidistic said:
Why? According to stack overflow it should return std::bad_alloc in that particular case, not 0.
0 would mean ''success'', or not, if anything?
std::bad_alloc is not a "value that is returned" in that case, it is an "exception that is thrown/raised/whatever verb appropriate" in that case, these are two different things. Actual value returned is nullptr, and when you print it, you might get, I don't know what exactly, perhaps 0. But what you cannot do, is to interpret that as a valid pointer to a memory location, because that is not what it is. Otherwise, the allocation would not be failed. No?
 
Last edited:
  • #7
I think you are confused about what is happening. You allocated memory for x, but you didn't assign any value for the memory allocated at that location. So when you print out the value at that location, it is whatever garbage happens to be at that location, often 0, but it can be anything. Also, when you allocate memory for the array, that memory is different from the memory you allocate in your "generate_int_and_pointer" function. I modified you program slightly and below is the modified program and the output. I think it all makes sense. Please look at this and tell me what confuses you.

C++:
#include <iostream>
#include <thread>
#include <cstdio> // Include for printf
#include <cstdlib>
#include <sstream>
#include <string>

long int generate_int_and_pointer() {
// Allocate memory for an integer
int* x = new int [1];
std::cout << x << ": memory address of x in hexadecimal.\n";
//printf("%ld : Address in memory (decimal)\n", reinterpret_cast<long>(x));
std::cout << "Value at memory location " << x << ": " << x[0] << std::endl;

return reinterpret_cast<long>(x);
}

long int* save_addresses(int n) {
    long int* addresses_array = new long int[n];
for (int i=0; i< n; i++) {
  addresses_array[i] = generate_int_and_pointer();
  std::cout << "Value at array location " << &addresses_array[i] << ": " << addresses_array[i] << std::endl;

 }

return addresses_array;
}

int main()
{   
  std::cout<<" Running only generate_int_and_pointer"<<std::endl;
  generate_int_and_pointer();
  std::cout<<" Running save_addresses"<<std::endl;
  save_addresses(5);
}

Output:

Running only generate_int_and_pointer
0x600001120000: memory address of x in hexadecimal.
Value at memory location 0x600001120000: 0
Running save_addresses
0x600001120010: memory address of x in hexadecimal.
Value at memory location 0x600001120010: 0
Value at array location 0x600001d2c000: 105553134223376
0x600001120020: memory address of x in hexadecimal.
Value at memory location 0x600001120020: 0
Value at array location 0x600001d2c008: 105553134223392
0x600001120030: memory address of x in hexadecimal.
Value at memory location 0x600001120030: 0
Value at array location 0x600001d2c010: 105553134223408
0x600001120040: memory address of x in hexadecimal.
Value at memory location 0x600001120040: 0
Value at array location 0x600001d2c018: 105553134223424
0x600001120050: memory address of x in hexadecimal.
Value at memory location 0x600001120050: 0
Value at array location 0x600001d2c020: 105553134223440
 
  • #8
fluidistic said:
As far as I understand, this number heavily depends on the OS and compiler, so if I could save those addresses in memory, I could possibly determine the OS and or compiler on which the program is running.
Almost certainly not. It mostly depends on what else is running on the system and using memory. Further, the language does not specify where the memory you ask for is coming from: it just gives it to you (or not).
 
  • #9
I am in a rush. Nope @phyz guy, I do not print the value of the int, which happens to be 0 in your case. I print the pointer's value in decimal. It never vanishes when I,execute the program over and over, no matter how quickly I rerun it. I get some 0 values when I try to run the program in a loop in a cpp code. The behavior is not the same as exiting the program and rerun it.
@Vanadium, much much less than I thought. I ran the program for a full day, with firefox, libreoffice, qt desigber and many other resources hungry programs (turned them on and off to see if I could see any difference) and the allocated memory didn't noticeably change of address during.the full day. Maybe it's possible to see some differences by using statistical tools, but visually on a graph I couldn't tell any difference whatsoever.
 
  • #10
fluidistic said:
I print the pointer's value in decimal.
Again, you store (and I assume, print) a pointer reinterpreted as a long. Unless "sizeof(long) == sizeof(*int)" this will loose information. What are the two sizeof for your setup?
 
  • #11
To the specific point, and int takes, say 4 bytes. If you have 4 bytes free between two processes, the OS may give them to you. If you start and stop a bunch of other processes, they are likely to ask for a lot more than 4 bytes, and that free space is always there.

But the more general point is that if the spec does not promise it, you cannot count on it. This is worth printing and taping to your monitor.
 
  • #12
OK, so I put back in your print statement to print the value of the address in decimal. See below. It still makes sense to me. What exactly is your question?

Running only generate_int_and_pointer
0x600002100030: memory address of x in hexadecimal.
105553150869552 : Address in memory (decimal)
Value at memory location 0x600002100030: 0
Running save_addresses
0x600002100040: memory address of x in hexadecimal.
105553150869568 : Address in memory (decimal)
Value at memory location 0x600002100040: 0
Value at array location 0x600002d04240: 105553150869568
0x600002100050: memory address of x in hexadecimal.
105553150869584 : Address in memory (decimal)
Value at memory location 0x600002100050: 0
Value at array location 0x600002d04248: 105553150869584
0x600002100060: memory address of x in hexadecimal.
105553150869600 : Address in memory (decimal)
Value at memory location 0x600002100060: 0
Value at array location 0x600002d04250: 105553150869600
0x600002100070: memory address of x in hexadecimal.
105553150869616 : Address in memory (decimal)
Value at memory location 0x600002100070: 0
Value at array location 0x600002d04258: 105553150869616
0x600002100080: memory address of x in hexadecimal.
105553150869632 : Address in memory (decimal)
Value at memory location 0x600002100080: 0
Value at array location 0x600002d04260: 105553150869632
 
  • #13
phyzguy said:
OK, so I put back in your print statement to print the value of the address in decimal. See below. It still makes sense to me. What exactly is your question?

Running only generate_int_and_pointer
0x600002100030: memory address of x in hexadecimal.
105553150869552 : Address in memory (decimal)
Value at memory location 0x600002100030: 0
Running save_addresses
0x600002100040: memory address of x in hexadecimal.
105553150869568 : Address in memory (decimal)
Value at memory location 0x600002100040: 0
Value at array location 0x600002d04240: 105553150869568
0x600002100050: memory address of x in hexadecimal.
105553150869584 : Address in memory (decimal)
Value at memory location 0x600002100050: 0
Value at array location 0x600002d04248: 105553150869584
0x600002100060: memory address of x in hexadecimal.
105553150869600 : Address in memory (decimal)
Value at memory location 0x600002100060: 0
Value at array location 0x600002d04250: 105553150869600
0x600002100070: memory address of x in hexadecimal.
105553150869616 : Address in memory (decimal)
Value at memory location 0x600002100070: 0
Value at array location 0x600002d04258: 105553150869616
0x600002100080: memory address of x in hexadecimal.
105553150869632 : Address in memory (decimal)
Value at memory location 0x600002100080: 0
Value at array location 0x600002d04260: 105553150869632
If you focus on the addresses in memory (in decimals), you can see the big ints I was talking about. As you can see, they don't differ too much. However if I call the function that generates them in a loop and save the results in an array, the first entry will be a big int like above, and the rest will be totally different, sometimes negative, and sometimes several entries are 0's.
On my machine at home I cannot reproduce this, however. I get what I would have expected, a list of such big ints without any problem. I won't have access to the machine where this was not the case (it had Ubuntu, and I have another Linux distro here on this machine). My question is why would I get a strange array where several entries are 0's sometimes. As if several ints were sharing the same address.
 
  • #14
fluidistic said:
If you focus on the addresses in memory (in decimals), you can see the big ints I was talking about. As you can see, they don't differ too much. However if I call the function that generates them in a loop and save the results in an array, the first entry will be a big int like above, and the rest will be totally different, sometimes negative, and sometimes several entries are 0's.
On my machine at home I cannot reproduce this, however. I get what I would have expected, a list of such big ints without any problem. I won't have access to the machine where this was not the case (it had Ubuntu, and I have another Linux distro here on this machine). My question is why would I get a strange array where several entries are 0's sometimes. As if several ints were sharing the same address.
It probably has to do with unsuccessful conversion of the address from hex to decimal, as @Filip Larsen said above. Why do you want to convert to decimal anyway?
 
  • #15
phyzguy said:
It probably has to do with unsuccessful conversion of the address from hex to decimal, as @Filip Larsen said above. Why do you want to convert to decimal anyway?
Just for the visual. The conversion is successful when I execute the code, except when I call the function to allocate memory in a loop, in which case it will always be successful in the first iteration and then never again. Hmm. I don't buy it unless there's an explanation.
 
  • #16
fluidistic said:
I don't buy it unless there's an explanation.
As mentioned several times now, the explanation was associated with a condition which you can easily test in your code: If sizeof(long) != sizeof(*int) on the architecture you have the issue on then your code is not "showing" the full pointer address. You mentioned you see negative numbers sometimes, so I this size mismatch is a likely source for the issue you see, but you have not given any other information so its only a guess. But is is so easy to verify for you, just print out those two sizeof!

In C++ you have to be mindful of the size of the types you use. I have no idea why you think its a good idea to reinterpret an address as an integer (instead of, say, simply print out the address in decimal), but if you insist then instead of your "long int" at least use something like unsigned long long which is guaranteed to be at least 64-bit, or include <cstdint> and use something like uint64_t which is always 64-bit.
 
  • #17
fluidistic said:
if I could save those addresses in memory, I could possibly determine the OS and or compiler on which the program is running.
When you take an aeroplane flight do you look at the labels when you pick up your baggage to find out what country you are in?
 
  • Like
Likes Nugatory and Vanadium 50
  • #18
I wish I could like @pbuk 's message twice.

Before we go too far down this path, have you looked at the results? 0x600001120000 is ~100 TB. Do you have that much memory installed?

If not, isn't it likely that the pointer is not a simple linear mapping of the physical address space? (In fact, Intel has done this for 4 decades)
 
  • Informative
Likes fluidistic

1. What is the purpose of pointers in C++?

Pointers in C++ are variables that store the memory address of another variable. They are used to indirectly access and manipulate data stored in memory, allowing for more efficient memory usage and dynamic memory allocation.

2. How does the operating system handle memory allocation?

The operating system manages memory allocation by dividing the available memory into smaller chunks and keeping track of which chunks are in use and which are free. When a program requests memory, the operating system will allocate a free chunk of memory to the program.

3. What is the difference between stack and heap memory allocation?

Stack memory allocation is used for storing local variables and function calls, and is managed automatically by the compiler. Heap memory allocation, on the other hand, is used for dynamic memory allocation and is managed manually by the programmer.

4. How do compilers handle memory allocation?

Compilers allocate memory for variables and data structures based on the programming language's syntax and semantics. They also optimize memory usage by reusing memory addresses and performing memory management techniques such as garbage collection.

5. How do you prevent memory leaks in C++?

To prevent memory leaks in C++, it is important to properly manage memory allocation and deallocation using tools such as smart pointers or manual memory management techniques. It is also important to thoroughly test and debug code to identify and fix any potential memory leaks.

Similar threads

  • Programming and Computer Science
Replies
3
Views
731
  • Programming and Computer Science
Replies
13
Views
2K
  • Programming and Computer Science
4
Replies
118
Views
6K
  • Programming and Computer Science
Replies
5
Views
885
  • Programming and Computer Science
Replies
23
Views
1K
  • Programming and Computer Science
Replies
19
Views
2K
  • Programming and Computer Science
Replies
4
Views
3K
  • Engineering and Comp Sci Homework Help
Replies
17
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
670
  • Programming and Computer Science
Replies
12
Views
1K
Back
Top