Why can't I copy an array using `=`?

I start learning C by reading K & R and going through some exercises. After some fights, I was finally able to complete Exercise 1-19 using the code below:

/* reverse: reverse the character string s */ void reverse(char s[], int slen) { char tmp[slen]; int i, j; i = 0; j = slen - 2; /* skip '\0' and \n */ tmp[i] = s[j]; while (i <= slen) { ++i; --j; tmp[i] = s[j]; } /* code from copy function p 29 */ i = 0; while ((s[i] = tmp[i]) != '\0') ++i; } 

My question is about the last bit of code in which the tmp char array is copied to s . Why does simple s = tmp; work instead s = tmp; ? Why do I need to iterate over an array index while indexing an index?

+7
c arrays
source share
9 answers

I may be just old and grumpy, but the other answers that I saw seem to be completely missed.

C does not perform array assignments, period. You cannot assign one array to another array with a simple assignment, unlike some other languages ​​(for example, PL / 1, Pascal and many of its descendants - Ada, Modula, Oberon, etc.). In fact, C does not have a string type. It has only character arrays, and you cannot copy arrays of characters (no more than you can copy arrays of any other type) without using a loop or calling a function. [String literals are not really considered a string type.]

Only temporary arrays are copied when the array is embedded in the structure, and you perform the structure assignment.

In my copy of K & R 2nd Edition, Exercise 1-19 requests the function reverse(s) ; in my copy of K & R 1st Edition, it was exercise 1-17 instead of 1-19, but the same question was asked.

Since pointers are not considered at this stage, the solution should use indexes instead of pointers. I believe this leads to:

 #include <string.h> void reverse(char s[]) { int i = 0; int j = strlen(s) - 1; while (i < j) { char c = s[i]; s[i++] = s[j]; s[j--] = c; } } #ifdef TEST #include <stdio.h> int main(void) { char buffer[256]; while (fgets(buffer, sizeof(buffer), stdin) != 0) { int len = strlen(buffer); if (len == 0) break; buffer[len-1] = '\0'; /* Zap newline */ printf("In: <<%s>>\n", buffer); reverse(buffer); printf("Out: <<%s>>\n", buffer); } return(0); } #endif /* TEST */ 

Compile this with -DTEST to enable the test program and not only have the reverse() function.

With the signature of the function asked in the question, you do not call strlen() twice on the input line. Note the use of fgets() - even in test programs, it is a bad idea to use gets() . The disadvantage of fgets() compared to gets() is that fgets() does not delete the ending newline where gets() does. The top of fgets() is that you are not getting an array overflow, and you can determine if the program detected a new line or if it ended with a space (or data) before meeting with a new line.

+20
source share

Your tmp array was declared on stack , and so when your method is complete, the memory used to store the values ​​will be freed due to scoping .

s = tmp means that s must point to the same memory location as tmp . This means that when tmp freed, s will still point to a now possible invalid free memory location.

This type of error is called a dangling pointer .

Edit: This is a non-freezing modifier, as indicated in the comments on this answer. The problem is that the expression s = tmp changes only what the parameter indicates, and not the one that was passed to the actual array.

In addition, you can do the opposite with one pass and without allocating an entire array in memory by simply changing the values ​​one by one:

 void reverse(char s[], int slen) { int i = 0; // First char int j = slen - 2; // Last char minus \n\0 char tmp = 0; // Temp for the value being swapped // Iterate over the array from the start until the two indexes collide. while(i < j) { tmp = s[i]; // Save the eariler char s[i] = s[j]; // Replace it with the later char s[j] = tmp; // Place the earlier char in the later char spot i++; // Move forwards with the early char j--; // Move backwards with the later char } } 
+8
source share

Because both s and tmp are memory destinations. If you s = tmp, both pointers point to the same array.

Let's pretend that

 char s[] ="ab"; /* * Only for explanatory purposes. * */ void foo(char s[]){ char tmp [] = "cd"; s= tmp; } foo(s); 

after s = tmp you will have

 s[0] : 'c' s[1] : 'd' s[2] : '\0' 

Despite the fact that both arrays have the same data, changing tmp affects both of them, since both arrays are actually the same. Both of them contain data that are in the same memory address. Therefore, changing any position of the tmp array or destroying the tmp array, s will be affected in the same way.

Finishing the loop over the array, you are moving part of the data from one memory address to another.

In my copy of K and R, the pointers are explained in chapter 4. A quick look at the first pages may help.

+4
source share

To finish the discussion, consider two other possible ways to change it as a string:

 void reverse(char string1[], char string2[]) { int i = 0, len = 0; while(string2[len] != '\0') // get the length of the string len++; while(len > 0) { string1[i] = string2[len-1]; // copy the elements in reverse i++; len--; } string1[i] = '\0'; // terminate the copied string } 

Or recursively:

 void reverse (const char *const sPtr) { //if end of string if (sPtr[0] == '\0') { return; } else //not end of the string... { reverse(&sPtr[1]); //recursive step putchar(sPtr[0]); //display character } } 
+1
source share

because tmp is a pointer, and you need to get a copy, not a link.

0
source share

In the case s = tmp, the value of tmp, which is also the starting address of the array, will be copied to s.

Thus, s and tmp will point to the same address in memory, which, I think, is not the goal.

greetings

0
source share

There is an interesting subflow in this thread about arrays and pointers. I found this link on Wikipedia with a peculiar piece of code showing how C can be "plasticine"!

 /* x designates an array */ x[i] = 1; *(x + i) = 1; *(i + x) = 1; i[x] = 1; /* strange, but correct: i[x] is equivalent to *(i + x) */ 

Of course, even more confusing in C, I can do this:

 unsigned int someval = 0xDEADD00D; char *p = (char *)&someval; p[2] = (char)0xF0; 

Thus, the interchangeability of pointers and arrays seems so deep in C that it is almost deliberate. What do everyone else think?

--- The original message --- s and tmp are both pointers, so s = tmp will simply make point s at the address where tmp lives in memory.
Another problem with what you pointed out is that tmp is a local variable, so it will become "undefined" when it goes out of scope when the function returns.

Make sure that you fully understand these three concepts, and you are not mistaken.

  • Scope
  • Difference between stack and heap
  • Pointers

Hope this helps and continues!

0
source share

Try experimenting and see what happens when you do these things:

 void modifyArrayValues(char x[], int len) { for (int i = 0; i < len; ++i) x[i] = i; } void attemptModifyArray(char x[], int len) { char y[10]; for (int i = 0; i < len; ++i) y[i] = i; x = y; } int main() { int i = 0; char x[10]; for (i = 0; i < 10; ++i) x[i] = 0; attemptModifyArray(x, 10); for (i=0; i < 10; ++i) printf("%d\n", x[i]); // x is still all 0's modifyArrayValues(x, 10); for (i=0; i < 10; ++i) printf("%d\n", x[i]); // now x has 0-9 in it } 

What happens when you change the array directly in attemptModifyArray , you just overwrite the local copy of the address of the array x . When you return, the source address is still in the main copy of x.

When you change the values ​​in an array in modifyArrayValues , you change the actual array, which has its address stored in modifyArrayValues local copy of x . When you return, x is still held in the same array, but you changed the values ​​in that array.

0
source share

A very direct answer would be - both s and tmp are pointers to a memory location, not the arrays themselves. In other words, s and tmp are memory addresses in which the array values ​​are stored, but not the values ​​themselves. And one of the common ways to access these array values ​​is to use indexes like s [0] or tmp [0].

Now, if you try to simply copy s = tmp, the memory address of the tmp array will be copied to s. This means that the original array s will be lost, and even the memory pointer s will now point to the tmp array.

You will understand these concepts well in due course, so keep reading the book. I hope this elementary explanation helps.

-2
source share

All Articles