3
// Example program
#include <iostream>
#include <string>

using namespace std;

int main()
{
    char **p;
    p = (char **)malloc(100);
    p[0] = (char *)"Apple";      // or write *p, points to location of 'A'
    p[1] = (char *)"Banana";     // or write *(p+1), points to location of 'B'

    cout << *p << endl;          //Prints the first pointer 
}

In the above code :

p[0] = (char *)"Apple"; 

seems to reserve memory automatically. There is no malloc. Is this C/C++ standard or compiler specific?

UPDATE 1 I am actually interested how it is in C and then in C++. It is just that I did not have a C compiler installed for the code above, so I used C++.

So p is allocated on the STACK pointing to a block of memory (array) in the HEAP where each element points (is a pointer) to a literal in the DATA segment? Wow!

Anton Andreev
  • 2,052
  • 1
  • 22
  • 23
  • [string literals](https://en.cppreference.com/w/cpp/language/string_literal) is a good place to start, at least as it pertains to C++. – clcto Sep 04 '19 at 20:51
  • 2
    this is not c this is c++. And in C++ you cannot cast string literals to non const char * – Jean-François Fabre Sep 04 '19 at 20:51
  • 1
    @Jean-FrançoisFabre yes you can, as the OP does in this example. The undefined behavior only comes when you try to modify the data it points to. – clcto Sep 04 '19 at 20:55
  • You're allocating an array of pointers to constants. If the pointed-to strings were dynamic, things get a bit more interesting. Also, there's rarely a reason to do this type of string storage in C++. (C is another matter.) – 3Dave Sep 04 '19 at 21:13
  • 1
    This is undefined behaviour in C++, you could use `new` rather than `malloc` – M.M Sep 04 '19 at 21:31
  • @eerorika [see here](https://stackoverflow.com/questions/40873520/), the assignment operator requires the left operand to refer to an object that exists already (not storage with no objects in it, as in this case) – M.M Sep 04 '19 at 21:40
  • @M.M yeah, I just realized that myself and added it to my answer. – eerorika Sep 04 '19 at 21:42

3 Answers3

5

seems to reserve memory automatically. There is no malloc.

Dynamic allocation is not the only way to acquire memory in C++.

The variable p has automatic storage. The string literals are arrays that have static storage. Objects with automatic, static or thread local storage are destroyed automatically. All variables have one of these three storage durations.

Automatic objects are destroyed at the end of the (narrowest surrounding) scope, static objects are destroyed after main returns and thread local objects are destroyed when the thread exits.

Is this C/C++ standard or compiler specific?

The example program is mostly standard, except:

  • You haven't included a header that is guaranteed to declare malloc.
  • You haven't created char* objects into the dynamically allocated memory, so the behaviour of the program is technically undefined in C++. See P.P.P.S. below for how to fix this.

P.S. It is quite unsafe to point at string literals with non-const pointers to char. Attempting to modify the literal through such pointer would be syntactically correct, but the behaviour of the program would be undefined at runtime. Use const char* instead. Conveniently, you can get rid of some of the explicit conversions.

P.P.S. C-style explicit conversions are not recommended in C++. Use static_cast, const_cast or reinterpret_cast or their combination instead.

P.P.P.S. It is not recommended to use malloc in C++. Use new or new[] instead... or even better, see next point.

P.P.P.P.S. It is not recommended to have bare owning pointers to dynamic memory. Using a RAII container such as std::vector here would be a good idea.

P.P.P.P.P.S. Your example program leaks the dynamic allocation. This is one of the reasons to avoid bare owning pointers.


So p is allocated on the STACK pointing to a block of memory (array) in the HEAP where each element points (is a pointer) to a literal in the DATA segment?

The language itself is agnostic to concepts such as stack and heap memory and data segment. These are details specific to the implementation of the language on the system that you are using.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

malloc does dynamic memory allocation. Here you have classic static memory allocation, where string constants will be allocated in data section of your binary (if I'm not mistaken). Compiler knows in advance how many bytes you need, so it will just allocate it during compilation. This is as opposed to malloc, where you can ask for any number of bytes calculated in runtime and unknown in advance.

Same with arrays that you declare with constant length, without using malloc.

alamar
  • 18,729
  • 4
  • 64
  • 97
  • 1
    "if I'm not mistaken" - you may be - many architectures don't have a "data section", or any sections at all. –  Sep 04 '19 at 21:06
  • I see, the data segment is different from the stack. – Anton Andreev Sep 04 '19 at 21:12
  • @AntonAndreev there could also be multiple data "segments" in completely different address spaces. On a Harvard architecture (vs von Neumann), for instance, the literal strings would be stored in code space, and the poorly-named `p` array would reside in one of many possible writable spaces. The string literals may not reside in the same address space or even on the same physical device. – 3Dave Sep 04 '19 at 21:16
  • ``Same with arrays that you declare with constant length, without using malloc`` Not quite. A statically-sized array that is non-const will still be located in writable space, since it's... well, writable. Stuffing that into a code segment, code space, or whatever it's called for your specific platform makes no sense. Even a `char *s="asdfasd'` can be modified, since it's non-`const`. – 3Dave Sep 04 '19 at 21:19
1

[This is the C answer, since the question was originally tagged [c] also. But it mostly applies to C++ as well.]

When you say

char *str = "text"

or, as in your code,

p[0] = "Apple";

the compiler does allocate memory for those strings "test" and "Apple". It definitely is not as if malloc was called, however. In particular, the memory where those strings are stored is not guaranteed to be (and, these days, typically is not) writable. And you can't pass those pointers to free or realloc -- because, again, they did not come from malloc in the first place.

This is a longstanding aspect of C (and, by extension, C++), true since forever and under any compiler.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • 2
    "and, by extension, C++", well, no `char *str = "text";` is illegal in C++. –  Sep 04 '19 at 21:09