C style string scoping question

Discussion in 'Mac Programming' started by CaptainHat, Jan 22, 2010.

  1. CaptainHat macrumors newbie

    Joined:
    Mar 8, 2007
    #1
    So I have a question about scoping and it's relation to pointer style C strings. Specifically, if you allocate a C string like:

    char* test = "this is a C string";

    since test is a char*, I'm guessing that this just sitting on the stack and that the string is also just a constant on the stack and that both of them will go out of scope when the function exits. I ran the following in XCode to test this as follows:

    char* createCString();

    int main (int argc, char * const argv[]) {
    char* test;
    test = createCString();
    char* other_string = "this is some other string";
    cout << test << endl;
    return 0;
    }

    char* createCString(){
    char* result = "this is a C style string.";
    return result;
    }

    and somehow it does in fact output "this is a C style string." So I'm wondering what exactly the scope of this style of C string is?

    Any help on this is appreciated b/c I'm kind of miffed. I tried reading the section on this in K&R but it didn't really help that much. Thanks for any help.
     
  2. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #2
    Perhaps it directly references the string from the compiled code itself?
     
  3. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #3
    Upon further reflection, I believe it works like this:

    The linker creates a header that defines the region where static values live. This region includes variables defined with "static" as well as all the string-type constants that would be created by the above code. When your app is loaded and run, the statics region is established in the appropriate manner. Where you say
    Code:
    char *test = "This is a C string";
    what is generated is code that reserves a space on the stack for test and assigns it the address of the predefined string in the static data region.

    Unix likes to keep code and data separate. This is a good™ thing.
     
  4. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #4
    Example code:

    Code:
    char *the_str(void)
    {
       char *test = "Looney bin";
       return test;
    }
    
    main()
    {
       char *a_str = "Hello";
       char *b_str = the_str();
    }
    
    
    The actual strings themselves are typically stored in a "constant strings" part of the program and are all accessible, assuming you know pointer. In the function "the_str()", the variable 'test' is indeed allocated on the stack and lost when the_str() returns. However, you returned the pointer to that constant string. The string itself is not stored on the stack, it's in the constant strings data area of the program.

    As a matter of fact, you probably cannot modify the string. You can't say:

    Code:
    char *the_Str(void)
    {
    char *test = "Looney bin";
    test[2] = 'x';
    return test;
    }
    because the actual memory holding the string is compiled into the program as readonly memory. If you want an actual string stored on the stack you can modify you would have to create one.

    Code:
    char *the_str(void)
    {
       char str[32];
       char *test = "Looney bin";
    
       strcpy(str, test);
       str[2] = 'x';
    }
    This is legal because you copied the constant string into an array on the stack. Notice you would *not* be allowed to return the pointer to 'str' from the function because that memory was allocated on the stack. It can't be used when you leave the function.
     
  5. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #5
    In C, C++ and Objective-C, a string literal like "This is a string" is actually the address of a static array of const char. Whether you write

    char* p = "A string";

    or

    static const char secret_array [] = { 'A', ' ', 's', 't', 'r', 'i', 'n', 'g', 0 };
    char* p = (char *) secret_array;

    produces _exactly_ the same result.
     
  6. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #6
    Ultimately, though, you should not get into the habit of using string constants. If you need to use a constant, do it something like this

    Code:
    
    #define  [B]aCStyleString[/B]  "this is a C style string."
    #define  [COLOR="Blue"]anotherString[/COLOR]  "this is some other string"
    
    char* createCString();
    
    int main (int argc, char * const argv[]) {
      char* test;
      test = createCString();
      char* other_string = [COLOR="Blue"]anotherString[/COLOR];
      cout << test << endl;
      return 0;
    }
    
    char* createCString(){
      char* result = [B]aCStyleString[/B];
      return result;
    }
    
    Using definitions in .h files makes projects much easier to manage as they inevitably get larger. In XCode, it also improves your workflow because if you have auto-complete, it finds and fills-in your definitions.
     
  7. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #7
    Scope and lifetime are two different things. The original post used the term "scope" when it was actually lifetime that was being tested.

    http://en.wikipedia.org/wiki/C_syntax#Storage_duration_specifiers

    http://frank.mtsu.edu/~csci117/manual/lab9/lab9.html

    http://hubpages.com/hub/Scope-and-Lifetime-of-Variables-in-Cpp


    Code:
    #include <stdio.h>
    
    static char *
    str1()
    {
      return "This will be static storage.";
    }
    
    static char *
    str2()
    {
      char str[] = "This will be auto storage (stack).";
      return str;  // produces a warning
    }
    
    static char *
    str3()
    {
      static char str[] = "This is static.";
      return str; 
    }
    
    int 
    main( int argc, const char * argv[] ) 
    {
      int autoOnStack[ 1 ] = { 0 };
      printf( "stack: %p\n", autoOnStack );
    
      char* str = "Outer str";
      printf( " str: %p %s\n", str, str );
    
      {
        char* str;  // scope & lifetime is limited to block
    
        str = str1();
        printf( "  str1: %p %s\n", str, str );  // %s is safe
    
        str = str2();
        printf( "  str2: %p\n", str );  // %s is dangerous: storage is gone
    
        str = str3();
        printf( "  str3: %p %s\n", str, str );  // %s is safe
      }
    
      printf( " str: %p %s\n", str, str );  // unaffected by str in block
    }
    
     
  8. CaptainHat thread starter macrumors newbie

    Joined:
    Mar 8, 2007
    #8
    Thanks everyone. This helped a lot. I (hopefully) think I understand what is going on now.
     

Share This Page