C Pointers and String constants

Hi,

Very basic question as I probably forgot how this works. I was testing rudimentary strcat function from K&R and I found different behavior while giving input in different manner -

#include <iostream>

using namespace std;

void strCat(char *s, char *t) {
    while(*s)
        s++;
    while((*s++ = *t++))
        ;
}

int main() {
    char p[] = "Hello ";
1->    char *s = "Hello ";                 //DO NOT WORK
2->    //s = p;                                   //WORKS
3->    //char s[] = "Hello ";              //WORKS
    char *t = "world!";
    strCat(s,t);

    cout << s << endl;
    return 0;
}

When I try to send string s as given on line by "1->", I get runtime exception. Otherwise if i try as per given on lines "2->" or"3->", it works!!!

Can anybody tell me why "1->" doesn't work??
James BondSoftware ProfessionalAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ozoCommented:
the destination must be writeable and have sufficient space
0
James BondSoftware ProfessionalAuthor Commented:
Why it is writable in char s[] case and not in char *s case??
0
ozoCommented:
The effect of attempting to modify a string literal is undefined.
In both cases, addressing beyond the bounds of an object is undefined
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

James BondSoftware ProfessionalAuthor Commented:
I know that. then why it works in case of char s[]?? I am using minGW g++ compiler on windows 8.
0
ozoCommented:
When behavior is undefined, the compiler is permitted to do anything.
0
ozoCommented:
Including overwriting something you haven't noticed yet.

By the way, K&R is an old standard, most C compilers use C89 or later, and your program does not even look like C because it uses C++ constructs.
0
James BondSoftware ProfessionalAuthor Commented:
I am not using old compiler. It is a c++ program strcat function is from k&r. Can you rewrite the method which you think will work?
0
ozoCommented:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main() {
    char p[] = "Hello ";
    char *t = "world!";
    char *s = (char *)malloc(sizeof(p)+strlen(t));
    strcpy(s,p);
    strcat(s,t);
    puts(s);
    return 0;
}


or

#include <iostream>
using namespace std;
int main() {
    char p[] = "Hello ";
    const char *t = "world!";
    string s(p);
    s += t;
    cout << s << endl;
   return 0;
}
0
James BondSoftware ProfessionalAuthor Commented:
Ok. Thanks. So direct pointer arithmetic won't work in new compilers on stack memory?
0
ozoCommented:
#include <string.h>
#include <stdio.h>
int main() {
    char s[13] = "Hello ";
    char *t = "world!";
    strcat(s,t);
    puts(s);
    return 0;
}
0
historychefCommented:
You apparently don't understand the difference between the declarations

char s[] = "Hello ";
char *t = "world!";

The first declares an array of (in this case) 7 chars (remember the \0 terminator!). The array is writable, so you could do things like

strcpy( s, "world!" );         /* This should work, and s[] now contains "world!\0" */

However, the second declaration defines t as a "pointer to char" and initializes it to point to the (anonymous) string "world!\0", which the compiler is entitled to put anywhere, including in the text (code) segment of your program, which is read-only. Therefore, trying to modify this will give you an error.
0
James BondSoftware ProfessionalAuthor Commented:
You mean s is pointing to fixed memory location but writeable. And t can point to any location but readonly?
0
ozoCommented:
What is pointed to by s will have auto storage duration and be writable.
What is pointed to by t will have a fixed location and it is implementation defined whether it will be writeable or readonly.
The value of s will be fixed and not writable.
The value of t will have auto storage duration and be writable.
0
James BondSoftware ProfessionalAuthor Commented:
I think you mean to swap s and t in your last 2 sentences above?
0
ozoCommented:
//The last 2 sentences are correct.
char s[] = "Hello ";
char *t = "world!";
s=t; // error
t=s; // valid;
0
James BondSoftware ProfessionalAuthor Commented:
What you are saying is somewhat contradicts with what historychef is saying.
0
ozoCommented:
Where do you see a contradiction?
0
James BondSoftware ProfessionalAuthor Commented:
In other words does below correct??

char s[] means char * const s i.e. constant pointer to char
char *t means char const *t i. e. pointer to constant char

at least as far as behaviour is concerned??
0
historychefCommented:
Let's break this down in detail. The definition

char s[] = "Hello ";

causes the compiler to allocate 7 bytes (usually -- actually 7 chars) of writable memory and call the address of the first byte "s". s has type "array of char". The initialization causes it to fill those 7 bytes with the characters 'H', 'e', 'l', 'l', 'o', ' ', '\0' (and, in fact, you could have gotten the same result with the definition

char s[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};

The string initialization is simply a shortcut for the more laborious array initialization shown above).

It should be obvious that you can later change the contents of any or all of those 7 bytes with an appropriate assignment; e.g., "s[0] = 'B'; s[5] = 'w';" are legal and will change the contents of the array to "Bellow\0". If you use the name of the array without a subscript, the compiler returns the address of the first element, so a reference to "s" (without subscript) is the same as a reference to "&s[0]". By now, you should have learned that, for C arrays, "s[j]" is equivalent to "*(s+j)" -- both return the value stored in the memory location 'j' elements past 's'. It is thus possible to write either 's[0]' or '*s' and get the same value, which in your original example is the character 'H'.

However, because 's' by itself is a value stored only in the compiler's symbol table, you can't change it: the statement 's = "world!";' (or, in ozo's example, 's = t;') is illegal.

Contrast all the above with what happens when you write

char *t = "world!";

You are now defining t as a variable of type "pointer to char" (so it occupies whatever memory a pointer on your computer requires). That memory (the pointer) is writable, so you can later reassign it to point to something else, as long as that "something else" is of the right type. So, the statement "t = s;" is completely legal, and is equivalent to "t = &s[0];". However, the string "world!" (plus its null terminator) has already been allocated and initialized by the compiler, somewhere in your program's memory. Compilers frequently allocate such "anonymous strings" in the text (code) segment of your program, which is not writable at run time. Indeed, many compilers will optimize such strings, so if you declare several pointers to refer to the same string, the compiler may only save one copy of that string. For example, the code

char *a = "Sample", *b = "Sample", *c = "Sample";

will probably store the string "Sample" only once, and initialize the three pointers a, b, and c to all point to that string. You can see that if you were allowed to change that string in some way, say with the statement

*(a+1) = 'i';           /* ILLEGAL! */

then all three variables would now reference the string "Simple" rather than "Sample".
On the other hand, you're perfectly free to later say

b = "Simple";

which will make b point to a compiler-initialized anonymous string containing the characters "Simple\0", without affecting either a or c. Note that this is the same as ozo's example of "t = s;" which, as he correctly stated, is legal.

Suggestion: Draw pictures of what's going on in memory. Use boxes for actual variables,  arrows to show what pointers point to, and labels next to the boxes to show the names by which the compiler knows those locations (i.e., what's in the compiler's symbol table).
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
James BondSoftware ProfessionalAuthor Commented:
Thanks for detailed approach. Appreciate that.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.