-3

Possible Duplicate:
Why can't I edit a char in a char*?

char *k ;

void ffill()
{
    char *d="ddddd";    
    *k=*d; //expecting to copy "ddddd" to *k
    cout<<k<<"\n";
    *d[1]=5; // trying to change array element
    cout<<k<<"\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffill();
    cout<<k<<"\n";
}

procedure fill initializes character array k with help of local variable. I'm not sure it copies "ddddd" variable pointer (that is wrong, because after automatic destruction of d memory is not safe) or it copies value and after this *k is initialized correctly.

How to aces *d array element? Compiler is not happy about *d[1]=5;

Community
  • 1
  • 1
vico
  • 17,051
  • 45
  • 159
  • 315

6 Answers6

17

(Disclaimer: this answer only covers C++. It is not recommended to ask for both C and C++, as both languages are quite different)

Prologue

char *k ;

This declares a pointer to a character.

"ddddd"

This expression has type char const[6], that is, an array of six constant characters. Expressions of this type can be implicitly converted to a pointer to the first element of the array. The type of that pointer is char const*, that is, a pointer to a constant character. A char const* is not convertible to a char*, because char* permits modification of the character it points to, while char const* doesn't.

char *d="ddddd";

Due to the rules outlined above, this statement is not correct. You should turn on the warnings on your compiler and it will warn you against this (ideally it would actually be an error, not just a warning). It should be char const* d = "ddddd"; if you really want a pointer or char d[] = "ddddd"; if you want an array. The second form doesn't need const because it makes a copy, and thus runs no risk of changing the original data, which is const.

*d

This expression involves the implicit conversion to char const* mentioned above, and then the indirection operator (the *) is applied to it, resulting in an expression of type char const&, that is, a reference to a constant character.

*k

Similar to *d, this performs indirection on a pointer. In this case, k is of type char*, so the resulting expression has type char&.

*k=*d; //expecting to copy "ddddd" to *k

The assignment assigns a single character, because it's assignment from a reference to a constant character into a reference to a character. It ends up assigning the first character of the string to the character pointed by k, which is... wait.

Where does k point to? It was never initialized! This is bound to end in tragedy.

Chapter 1

So, how do we get k to point somewhere? And how do we copy the whole string from d into that space?

To copy the six characters of the d array into k, we need space for six characters. The simplest way of doing this is to just make an array of six characters.

char k[6];

Now, how to copy the six elements? We can use the C library function strcpy, which copies null-terminated strings. This function needs a lot of care to use because:

  1. It requires the source to have a null ('\0') character marking the end; if the source does not have such a character, the behaviour is undefined and anything can happen. This is why the string "ddddd" has six characters and not 5: there's an implicit \0 character at the end that the compiler inserts for you.

  2. It requires the destination to have enough space for the whole source string including the null terminator. If the destination doesn't have enough space, the behaviour is also undefined and anything can happen.

This is how this function could be used to make a copy of the string:

std::strcpy(k, d);

Failure to meet either point #1 or #2 can result in anything, from the program seemingly working (if you're unlucky), to acting randomly in strange way, to simply crashing (if you're lucky).

Epilogue

Man, that was a lot of information. Do C++ programmers have to care about these matters all the time? That must be tiresome.

Well, C++ programmers can use std::string instead of character arrays and get a lot less hassle with this: we can make copies with the assignment operator, we don't need to track the correct sizes, we don't need to care for having the null terminators in place, we don't need to limit the size at compile time, and a bunch of other advantages.

std::string k;

void ffill()
{
    std::string d="ddddd";    
    k = d;
    cout<<k<<"\n";
    d[1]=5;
    cout<<k<<"\n";
}
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • +1 Some love for a nice answer. –  Jul 23 '12 at 15:26
  • **>string "ddddd" has six characters and not 5: there's an implicit \0** Does it means that after defining char j[5] or char* d="ddddd" I will always have sixth element that is always possible to access (in j case read/write in d - only read) by j[5] or *d[5]. And I always get 0 character in that place? And setting last element to '0' is automatic in case of char type array (for example in int array this doesn't works)? – vico Jul 24 '12 at 09:41
  • @user1501700 No, if you define `char j[5] = "ddddd"` the compiler should reject that, as six characters can't fit on an array of five. But yes, `d[5]` will be 0. And yes, this is a special rule just for string literals: arrays of int get no special treatment. – R. Martinho Fernandes Jul 24 '12 at 09:47
1

With C programming langage, you should use an array rather than a pointer (because it may point to a read-only string). For example :

char *k;

void 
fill(void)
{
   char d[] = "ddddd";
   k = d;
   d[1] = '5'; // Did you mean '5' ? 
}
md5
  • 23,373
  • 3
  • 44
  • 93
  • Well, that's another way to put it, nice and easily. – ATaylor Jul 23 '12 at 14:55
  • But this doesn't really *copy* anything but the pointer itself. – Blagovest Buyukliev Jul 23 '12 at 15:00
  • @BlagovestBuyukliev No, it doesn't. But look at the question, that's apparently exactly what the OP wants. He wants to copy the pointer, change something at the copy and then see the change happen at the original pointer. – ATaylor Jul 23 '12 at 15:03
  • @ATaylor The problem is that this solution assigns a global pointer to point at a local array. Using the global pointer later is a Bad Thing(TM)! – Code-Apprentice Jul 23 '12 at 15:28
  • @Code-Guru Heh...yes, of course. I never said this was the 'right' way to do it. (I have an answer out there myself). I merely said, that this is about what the OP wanted...for whatever reason. But I get what you mean. I really do. – ATaylor Jul 23 '12 at 18:28
1

Like Martinho Fernandes already stated: It seems like you're trying to use 'std:string', instead of char arrays.

char k[20] ; //*k doesn't allocate any memory for you to use.

void ffill()
{
    char *d="ddddd";    //This works, since it points to the constant character string in your code. But it can not be altered in any way. (It's a 'const char *')
    strcpy(k, d);       //This standard function copies the content of one pointer to another.
    cout<<k<<"\n";      //Not too sure, but it should work,
    k[1]=5;             //k is the 'changeable memory, not 'd'.
    cout<<k<<"\n";
}
ATaylor
  • 2,598
  • 2
  • 17
  • 25
1

There are several things going on here that you need to be aware of. Let me try to explain:

char *k ;

This line declares a variable called k which is a pointer to a character. However, it is not initialized to point to anything. Trying to use an uninitialized pointer will result in undefined behavior.

void ffill() 
{ 
    char *d="ddddd";

This line declares a variable named d which is also a pointer to a character. At the same time, you initialize the pointer to point to a constant character array (also called a c-string) that contains 5 'd' characters and a terminating NULL character (so the array has 6 elements).

    *k=*d; //expecting to copy "ddddd" to *k 

This line uses the dereference operator (*). This operator copys the character pointed to by d and places it at the address pointed to by k. As I noted above, this will result in undefined behavior since the address in the pointer k has not been initialized.

    cout<<k<<"\n";
    *d[1]=5; // trying to change array element

First of all, you are trying to assign an int to a char. Both C and C++ allow this, but you probably won't get what you expect. In this case, you are trying to replace the second 'd' character with the character code 5. In ASCII, this is a non-printing character.

Also, since d points to a c-string constant, trying to change its elements results in undefined behavior.

    cout<<k<<"\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
    ffill();
    cout<<k<<"\n";
}

There are some other issues with copying one c-string to another, but this is all the detail I will go into here. As other people mention, using std::string is simpler. However, I also believe that learning how to use c-strings is very educational and can improve your coding skills.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
0

You need to declare d as an array and not a pointer.:

char d[]
d[1] = '5';   // d is a char array, so did you mean the character '5'?

And change *k=*d; to k = d; //This will copy the value of the pointer

Chris Dargis
  • 5,891
  • 4
  • 39
  • 63
  • To be perfectly honest, I don't know if that would work. Isn't 'd' pointing to a read-only memory? – ATaylor Jul 23 '12 at 14:57
  • @ATaylor: Why is `d` read only? – Chris Dargis Jul 23 '12 at 15:02
  • I will be honest, I am not entirely sure about this issue, but as far as I know, all operations on memory need to be performed on allocated memory, either by declaring it as a variable (array) or with 'malloc' or 'new' (in C++). This pointer 'd' points to a const char, which is locked in program memory. I don't think we're supposed to change that. But again: Not sure. – ATaylor Jul 23 '12 at 15:06
  • So you're saying, that the memory for that string is automatically put on the stack and can thereby be modified like any other variable, did I get that right? Well, if that's true (which might as well be), you're correct. Altering it works just fine. – ATaylor Jul 23 '12 at 15:16
  • @ATaylor: No. My apologies. You were correct. My answer has been updated. :) – Chris Dargis Jul 23 '12 at 15:17
  • Ah, I see :) Good, I was already beginning to wonder. :) I've been getting a lot of 'getting taught better' on SO ever since I joined...well, fortunately for me, I already knew that I know nothing before that, otherwise I probably would've been out the door already :D – ATaylor Jul 23 '12 at 15:19
0

Let's see:

*k=*d; //expecting to copy "ddddd" to *k

This won't copy the "string", only tries to set the memory pointed by k to the first character of d. If it is not initialized, then it will fail badly.

*d[1]=5; // trying to change array element

This will also fail. First of all, this is a double indirection. The d[1] = 5; would be betted, but that would also fail, because the string is most probably stored in read-only memory.

Use string instead.

Matzi
  • 13,770
  • 4
  • 33
  • 50