-2

This is from my Computer Science Class

"This is dangerous (and officially deprecated in the C++ standard) because you haven't allocated memory for str1 to point at."

            jD3V's Computer Science Professor

The Quote Above is Referring to this Line of Code

    char* str1 = "Hello world";

To be clear:

I Get that using a pointer, as shown in the Line of Code above, is deprecated. I also know that it shouldn't appear in my code.

The Part I Don't Get:

The example line of code — char* str1 = "Hello world"; — works, and that surprises me.

It says that no memory has been allocated for the pointer to point at, though the pointer could still be accessed to obtain the C-String "Hello World". I am unaware of another place in memory, though my guess is that there has to be one, because if the following statement doesn't exist on the heap — "and its not placed in the stack according to my debugger" — then it must live in another memory location.

I am trying to be able to understand, and locate where the variables I declare are at in memory, and I am unable to do that here.

I would like to know...

In the example I showed above, where is the string "Hello World", and the str1 pointer that points at it, located in memory, if not in the Heap, or on the Stack?

Biffen
  • 6,249
  • 6
  • 28
  • 36
JΛYDΞV
  • 8,532
  • 3
  • 51
  • 77
  • 9
    Maybe this is a really oblique way of saying it should be `const char *str=…;`? – Davis Herring Oct 05 '21 at 02:58
  • The compiler allocated memory (probably static memory) containing the characters "Hello world", and `str` points to that memory. That's how string literals work. So I think your professor is confused, or is talking about something else. ("Deprecated" could indeed refer to the missing `const`.) – Nate Eldredge Oct 05 '21 at 03:00
  • My compiler complains about `char*` pointing to a `char const[]` array of memory. Probably what your professor was referring to. – Eljay Oct 05 '21 at 03:02
  • 1
    What _is_ "dangerous and deprecated" is the conversion of a char array literal to a non const pointer, not the fact that no (dynamic) allocation took place. – Etienne de Martel Oct 05 '21 at 03:04
  • 1
    @JΛY-ÐΞV `char* str = "Hello world"; str[0] = 'x';` -- Try that program. Don't be surprised if it crashes and burns, even though it looks valid. – PaulMcKenzie Oct 05 '21 at 03:08
  • Helpful reading: [String Literal](https://en.cppreference.com/w/cpp/language/string_literal) – user4581301 Oct 05 '21 at 03:25
  • A string literal is specified by the standard as being represented as an array of `char` (so `"Hello"` would be an array of six `char`, including the letters and a terminating nul character i.e. `'\0'`) with static storage duration. Practically, that means it occupies some area of memory for as long as the program is running, so the address (of its first character) can be stored in a pointer. – Peter Oct 05 '21 at 03:27
  • 1
    @Ruks String literals have static storage duration, not automatic. They are not on the stack. Something like `const char* f() { return "Hello, world"; }` is perfectly valid. – Igor Tandetnik Oct 05 '21 at 03:32
  • Is this correctly tagged? This is "dangerous, and deprecated" C, and *invalid* C++ – Caleth Oct 05 '21 at 08:05
  • Related, if not a dupe: https://stackoverflow.com/questions/7903551/when-to-use-const-char-and-when-to-use-const-char – Bob__ Oct 05 '21 at 09:12
  • there is no C/C++ language, choose one – 0___________ Oct 05 '21 at 12:06

3 Answers3

2

[Disclaimer: I wrote this answer when the question was tagged both [c] and [c++]. The answer is definitely different for C versus C++. I am leaning somewhat towards C in this answer.]

char* str = "Hello world";

This is perfectly fine in C.

According to my CS Professor, in reference to the statement above, he says...

"This is dangerous (and officially deprecated in the C++ standard) because you haven't allocated memory for str to point at."

Either you misunderstood, or your professor is very badly confused.

The code is deprecated in C++ because you neglected to declare str as being a pointer to unmodifiable (i.e. const) characters. But there is nothing, absolutely nothing, wrong with the allocation of the pointed-to string.

When you write

char *str = "Hello world";

the compiler takes care of allocating memory for str to point to. The compiler behaves more or less exactly as if you had written

static char __hidden_string[] = "Hello world";
char *str = __hidden_string;

or maybe

static const char __hidden_string[] = "Hello world";
char *str = (char *)__hidden_string;

Now, where is that __hidden_string array allocated? Certainly not on the stack (you'll notice it's declared static), and certainly not on the heap, either.

Once upon a time, the __hidden_string array was typically allocated in the "initialized data" segment, along with (most of) the rest of your global variables. That meant you could get away with modifying it, if you wanted to.

These days, some/many/most compilers allocate __hidden_string in a nonwritable segment, perhaps even the code segment. In that case, if you try to modify the string, you'll get a bus error or the equivalent.

For backwards compatibility reasons, C compilers cannot treat a string constant as if it were of type const char []. If they did, you'd get a warning whenever you wrote something like

char *str = "Hello world";

and to some extent that warning would be a good thing, because it would force you to write

const char *str = "Hello world";

making it explicit that str points to a string that you're not allowed to modify.

But C did not adopt this rule, because there's too much old code it would have broken.

C++, on the other hand, very definitely has adopted this rule. When I try char *str = "Hello world"; under two different C++ compilers, I get warning: conversion from string literal to 'char *' is deprecated. It's likely this is what your professor was trying to get at.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
-1

Summary:

  • "any strings in double quotes" are const lvalue string literals, stored somewhere in compiled program.

  • You can't modify such string, but you can store pointer to this string (of course const) and use it without modifying:

    const char *str = "some string"

    For example:

    int my_strcmp(const char *str1, const char *str2) { ... }
    
    int main() 
    {
        ...
    
        const char *rule2_str= "rule2";
    
        // compare some strings
        if (my_strcmp(my_string, "rule1") == 0)
            std::cout << "Execute rule1" << std::endl;
        else if (my_strcmp(my_string, rule2_str) == 0)
            std::cout << "Execute rule2" << std::endl;
    
        ...
    }
    
  • If you want to modify string, you can copy string literal to your own array: char array[] = "12323", then your array will ititialize as string with terminate zero at the end:

    Actually char array[] = "123" is same as char array[] = {'1', '2', '3', '\0'}.

    For example:

    int main()
    {
        char my_string[] = "12345";
        my_string[0] = 5; // correct!
    
        std::cout << my_string << std::endl; // 52345
    }
    

    Remember that then your array will be static, so you can't change it's size, for "dynamic sized" strings use std::string.

Moshe Groot
  • 111
  • 9
  • Not all string literals are `const lvalues`. You CAN store a non-const pointer to a string literal. Using of `char str[]` is rather different then `char* str`, so string literal here becomes `lvalue`. – korzck Oct 05 '21 at 08:13
  • 1
    Actually yes, you can store pointer not as `const`, but string will be still unmodifiable (so `const` here is for better code). But you shouldn't think about `char str[]` as about *"how to get string as modifiable lvalue"*, you should think about it as *"initializing static array with chars from string"*, like `int numbers[] = {1, 2, 3, 4, 5};`, and of course this array is modifiable by default. – Moshe Groot Oct 05 '21 at 08:31
  • `char str[]` is not something "static". It just has lvalues with certain address. Actually this array of chars is called **C-Style strings**, so yeah i can use it as modifiable string lvalue ;) – korzck Oct 05 '21 at 08:39
  • What do you mean by saying "it just has lvalues with certain address" (and why many value*s*)? Creating string as `char str[]` is just copying address of some modifiable lvalue string? Well, it's not true, see: https://godbolt.org/z/13Es8rde6. It's using some string literal from special data block of programm and copying it into a *static array* like as in `int arr[]` case. Or am I wrong? :\/ – Moshe Groot Oct 05 '21 at 09:20
  • Nope, copying strings into c-strings is different. Its better to use functions from std header `` like `strcpy()`. When i said "it just havs lvalues with certain address" i meant that you can access str elements with their address `*(str+n)`, where `n` is nth element of the array. – korzck Oct 05 '21 at 10:30
  • `strcpy` is using for manual copying, but we are talking now about `initializing` of c-string (actually, in our case it's static array of chars with terminate null at the end (of course you can put some symbols after it, but...)) and as I said, it just copying string literal from special memory block of program. If you are not agree, thus please show the difference. – Moshe Groot Oct 05 '21 at 10:49
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/237824/discussion-between-pp189-aka-mgroot-and-korzck). – Moshe Groot Oct 05 '21 at 11:05
  • Be careful with the term *static* because it means a lot of things. In this case you mean statically sized. – user4581301 Oct 05 '21 at 18:23
  • Yes, in this context we were talking about arrays, and *dynamic/static arrays* are common terms here – Moshe Groot Oct 06 '21 at 05:53
-3

The problem is in lvalue and rvalue. lvalue defines locator value and it means that it has a specified place in memory and you can easily take it. rvalue has undefined place in memory. For example, any int a = 5 has 5 as rvalue. So you cannot take the address of an rvalue. When you try to access the memory for char* str = "Hello World" with something like str[0] = 'x' you will get an error Segmentation fault which means you tried to get unaviable memory. Btw operators * and & are forbidden for rvalues, it throws compile time error, if you try to use them.
The lvalue of "Hello World" is stored at the programms segment of memory. But it is specified so, as the programm can't modify it directly.

korzck
  • 198
  • 9