1

So the title is my question. In memory, arguments can be located on the stack or heap depending on how they are initialized, but how is hard-coded information dealt with?

As an example, I will use the constructor for ifstream

What is the difference between this:

void function(){

    ifstream infile("home/some/file/path");

}

vs

void function(char* filePath){

    ifstream infile(filePath); //filePath points to a character array which contains home/some/file/path

}

Could any memory implications arise from the use of one over the other? (Multithreading could lead to heap corruption if the char* isn't free'd correctly? etc).

I am just trying to understand the difference and possible implications so I can apply the answer to a larger problem. All insight is welcome and feel free to correct me if I've made any incorrect statements/assumptions!

trincot
  • 317,000
  • 35
  • 244
  • 286
Sean Sen Wang
  • 193
  • 1
  • 1
  • 12
  • 2
    Really would depend on what `filePath` is and how it's created. But heap corruption is not caused by something not being `free`'d. Heap corruption is caused by bad code writing outside of the buffer that it allocated. – Mats Petersson Aug 19 '13 at 19:44
  • 1
    In your first example, the string will be put in the read-only-area of the process. So there is nothing that can do damage there. – bash.d Aug 19 '13 at 19:47
  • @MatsPetersson If you don't mind me asking, how many different ways are there to define a `char*`? I know you can do things like `char* foo = (char*)malloc(16)`, but what other, let's say popular, ways are there, and how would it affect memory? – Sean Sen Wang Aug 19 '13 at 19:49
  • 1
    You could be calling `function("home/some/file/path")` for example [although technically it should be `const` - but then if you pass it straight to `ifstream`, it's not an issue). It could be `char str[] = "some/file/path; function(str); "`, it could be `function(argv[2])` in `main`. That is far from a complete list, but there is only so much space in a comment. There are LOTS of ways that a `char *` can end up in your `function`. – Mats Petersson Aug 19 '13 at 19:52
  • @bash.d If the `char` pointer only pointed at a character array and was never "edited", only to be used as a file path essentially, what possible ways could the data being pointed to change? (Some function writing out of bounds perhaps?) – Sean Sen Wang Aug 19 '13 at 19:53
  • @SeanSenWang The OS will usually interrupt this with SIGSEGV (or the like) because you are trying to write a read-only portion of the process. So there should nothing corrupt the string withoug causing a crash. – bash.d Aug 19 '13 at 19:55
  • Could the use of a complex data structure, such as `std::vector` which automatically adjusts heap space cause a problem with using the non-literal method? For example, if I stored the contents of `ifstream infile` in a `std::vector`? – Sean Sen Wang Aug 19 '13 at 20:11

3 Answers3

2

Literals (which is what your first example shows) are placed into the static initialization portion of the executable (which is why, if you are on a *Nix system), you can use the command strings and obtain a list of all the literals in the application.

Your 2nd example should actually be modified to

void function(const char* filePath) { ... }

Unless you are going to modify the pointer in the function. The memory for that function can come from anywhere (a string literal being passed into the function, a constant string declared somewhere else in the application, a string stored in memory and inputted from the command line or console, etc.)

The primary issue you will run into with Multithreading here is if 2+ threads are attempting to load the same file at the same time. It may not be a problem if they are all reading it, but if you have a thread that wants to write to it and obtains an exclusive lock on the file, the other threads will deadlock. This isn't directly related to your strings question, though.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Thank you, that was very well explained. I will leave this question unanswered for now though because I would like to discuss it further :) – Sean Sen Wang Aug 19 '13 at 19:57
1

Others have pretty well covered that a literal string is stored in some read-only memory in the executable, and the pointer to char is just pointing directly at that memory.

Whether your second option is "good", "bad" or "none of the above" depends highly on what the origin of filePath is.

Clearly, if some code is doing char *filename = new char [x]; strcpy(filename, "..."); then there needs to be a corresponding delete [] filename; - and the x needs to be long enough for the string "..." to fit.

It is safer to use std::string in this case, as any allocation is dealt with by the class, and the de-allocation dealt with in the destructor.

If we throw threads into the equation, we will also have to worry about where the strings are defined. In a class that has only one instance, as a global variable or on the stack. Only "stack" is safe, and with restrictions: if you pass a pointer to char * from main [or some other function before the thread is created] into the thread, you could have all sorts of "fun" with memory being allocated multiple times into a single string, data being overwritten by other threads, and what have you. Of course, if the threads aren't CHANGING the data, there is also no problem with global variable or stack from outside the thread.

This is what I meant by "it depends on how the string is created". The details are definitely what matters here.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

The "hard-coded" or literal values are usually part of the instructions of the program. For example if I do something like

int i = 0;

the value of 0 is loaded using assembly commands at the architectural level. So what I am getting at is that they are handled by the compiler and program, and probably either will use no memory at all, or be on the stack.

For the values such as char*, first off I would recommend using strings, as they handle the memory allocation accordingly, but large strings are often stored on the heap, while small strings (less than 7 chars or so) can be optimized to be handled on the stack (unless "new" is involved).

pippin1289
  • 4,861
  • 2
  • 22
  • 37