[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 220
  • Last Modified:

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??
0
James Bond
Asked:
James Bond
  • 9
  • 9
  • 2
2 Solutions
 
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 
James BondSoftware ProfessionalAuthor Commented:
Thanks for detailed approach. Appreciate that.
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 9
  • 9
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now