#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    27
    Rep Power
    0

    Question Const char * pointer problem with definitions


    what is the difference between the definitions
    const char *substring;
    char * substring;

    what i know is const char*substring is used to store string literals
    but same is the case with simple character pointer
    i.e we cannot alter the character pointer values.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2012
    Posts
    156
    Rep Power
    33
    After
    Code:
    const  char *sub1;
    char *sub2;
    The compiler makes sure you do not try to change whatever sub1 points to, but allows you to change whatever sub2 points to.

    If you don't lie to the compiler (always a good idea!) it works great:
    Code:
    const char *sub1 = "unmodifiable string literal";
    char array[] = "string literal which gets copied";
    char *sub2 = array;
    
    sub1[7] = 'X'; /* compiler rightfully complains */
    sub2[7] = 'X'; /* compiler righfully allows this */
    If you lie to the compiler (always a very bad idea!) you're on your own:
    Code:
    const char *sub1 = "unmodifiable string literal";
    char *sub2 = "unmodifiable string literal";
    
    sub1[7] = 'X'; /* compiler righfully complains */
    sub2[7] = 'X'; /* compiler doesn't complain */
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    27
    Rep Power
    0
    I do agree that it there will be no compilation error but the code rises runtime error.
    this is my program for which i got runtime error

    #include<stdio.h>
    #include<conio.h>

    void main()
    {
    char *sub ="Am a techpie";
    sub[2] = 'h';
    printf("%s",sub);
    getch();
    }
    It got compiled but it raised runtime error
    An unhandled exception of type 'System.AccessViolationException' occurred in fileread.exe

    Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  6. #4
  7. I'm Baaaaaaack!
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Jul 2003
    Location
    Maryland
    Posts
    5,538
    Rep Power
    243
    In a lot of modern compilers even though your 'sub' is not marked as const, the compiler treats it as such and thus access is prohibited.

    My blog, The Fount of Useless Information http://sol-biotech.com/wordpress/
    Free code: http://sol-biotech.com/code/.
    Secure Programming: http://sol-biotech.com/code/SecProgFAQ.html.
    Performance Programming: http://sol-biotech.com/code/PerformanceProgramming.html.
    LinkedIn Profile: http://www.linkedin.com/in/keithoxenrider

    It is not that old programmers are any smarter or code better, it is just that they have made the same stupid mistake so many times that it is second nature to fix it.
    --Me, I just made it up

    The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man.
    --George Bernard Shaw
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    To elaborate, the memory space that your process is given it itself organized into different -- let's call them "segments" -- each of which has its own functions and properties (ie, whether they're read-only (RO) or read-write(RW)). You can learn what these are if you have your compiler/linker generate a link map. Details will vary between compilers, but from the link map generated by Visual C++ v1.5.2 (which link maps I've worked with), there the BBS which contains initialization data (RO), STACK for the stack (RW), DATA for the global variables and static local variables (RW), HEAP for the heap and dynamic allocation (RW), and TEXT which contains the program's executable code plus literals (RO).

    Now, when you declare this:
    char *sub ="Am a techpie";
    what I'm used to having happened is that the compiler created a literal string in TEXT and initialized sub to point to it. That means that the string itself is read-only because it's in a read-only segment of your process' memory space. Because it belongs to your process, your program can access it, but because it's in a read-only memory segment it cannot be modified.

    Again, this may not hold true with all compilers, but that's been my experience on Windows/DOS boxes.
  10. #6
  11. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,607
    Rep Power
    4247
    Originally Posted by dwise1_aol
    Again, this may not hold true with all compilers, but that's been my experience on Windows/DOS boxes.
    Windows yes (on newer version). DOS and really ancient Windows versions didn't have memory protection and it was possible to insert into *sub without crashing the program.

    One more point that no one has brought up yet is that if the variable is declared as const char * vs. char * is:
    Code:
    const char *foo = "This is a string";
    char *bar = "This is a string";
    
    foo[7] = 'x'; // Compiler won't even compile this
    bar[7] = 'x'; // Compiler will compile this. Any segfaults may happen at runtime.
    Declaring the variable as const char * protects you from yourself, because the compiler will be able to warn you that you've written some bad code and are overwriting something that you don't mean to overwrite. If you declare it as a char * (like the example for 'bar' above), the compiler won't complain and the error will only occur at runtime. Worse, if you have it inside an if condition:
    Code:
    if (somecondition()) {
        bar[7] = 'x'; // Will compile file, may segfault
    }
    then the code will only segfault under certain conditions when somecondition() returns true, so it will be harder to discover that you have a bug in your code.

    Whereas, if you declare it as a const char *
    Code:
    if (somecondition()) {
        foo[7] = 'x'; // Won't even compile
    }
    this code won't compile at all, so you can catch the error way earlier in the development stage.
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    Scorpions:

    OK, I normally refer to the Microsoft line (not including OS/2) as "Windows/DOS". That is keeping in mind the console emulation of "DOS" which allows us to run DOS apps (so long as the OS supports it -- Win7 64-bit won't, whereas Win7 32-bit should still). However, you do raise a valid point that the entire environment changed with Win95 and that the protections of Win32/64 were not in effect in MS-DOS. In light of that, I acknowledge that I should consider using the term "Windows" instead of "Windows/DOS".

    To summarize the rest of your reply, I would write a general rule:
    Use the features of the language to protect yourself from yourself by detecting errors at compile-time instead of being surprised at run-time.
    By adopting good programming practices that make use of the language's features (which were put there for a reason) to protect against bugs, you can save yourself a lot of heart-ache later on.

    Our example here is the use of const declarations that will trap at compile-time any violations you might commit against that const-ness. Anyone who wonders why that should be important should re-read your message here.

    Another example is the ability in C++ to declare array dimensions with const declarations rather than being restricted to macros (eg, #define MAX_ARRAY_SIZE). In C++, that allows you to test the type of an array dimension in order to ensure that it's valid. But C doesn't allow that, so it's stuck with macros that replace text in the source code and can lead to code that compiles differently than intended unless you use proper C programming practices. Though even if you do use proper C programming practices you still can't test a macro's datatype. And if you code C++ as you do C (ie, use macros instead of const declarations), then you are not using the features of the language to your benefit.

    Every programming language is designed based on a certain philosophy. I was a Pascal programming for a decade before I switched to C/C++ (though I first learned C when Borland's Turbo C was first released -- when I was laid off in 1987, I bought that compiler to learn C for my job hunt, but I got my next job based on my Pascal experience). Pascal was designed by an academic as a tool for teaching structured programming (the really hot buzz-word when I left college in 1982). As a result, it strove for "self-documenting code", meaning that you used full meaningful procedure/function and variable names, which, combined with the BEGIN and END reserved words, made Pascal code a bit verbose. My impression of C, especially when I first encountered atoi(), was that it was written by practicing programmers who hated to type so they abbreviated everything as much as possible.

    Many modern languages have the philosophy of protecting the programmer against himself. C, written by experienced programmers wanting to do what they wanted with minimal restrictions, has the philosophy that the programmer knows what he is doing. Which places a lot of responsibility on the programmer. Which makes it all the more important to adopt good programming practices.

IMN logo majestic logo threadwatch logo seochat tools logo