Copy structure with inline element in C

I have a simple structure containing a string defined as a char array. I thought that copying an instance of a struct to another instance using the assignment operator would just copy the memory address stored in the char pointer. Instead, it appears that the contents of the string are being copied. I put together a very simple example:

#include <stdio.h>
#include <string.h>

struct Test{
  char str[20];
};

int main(){

  struct Test t1, t2;
  strcpy(t1.str, "Hello");
  strcpy(t2.str, "world");
  printf("t1: %s %p\n", t1.str, (char*)(t1.str));
  printf("t2: %s %p\n", t2.str, (char*)(t2.str));
  t2 = t1;
  printf("t2: %s %p\n", t2.str, (char*)(t2.str));
  return 0;
}

      

Compiling this code with gcc 4.9.2 I get:

t1: Hello 0x7fffb8fc9df0
t2: world 0x7fffb8fc9dd0
t2: Hello 0x7fffb8fc9dd0

      

As I understand it, after t2 = t1

t2.str points to the same memory address that it specified before the assignment, but now inside that address, there is the same string found inside t1.str. So it seems to me that the contents of the string were automatically copied from one memory location to another, which I thought C wouldn't do. I think this behavior is caused by the fact that I have declared str as char[]

, not as char*

. Indeed, when trying to assign directly one string to another using t2.str = t1.str

this error:

Test.c: In function ‘main’:
Test.c:17:10: error: assignment to expression with array type
   t2.str = t1.str;
      ^

      

which makes me think that in some cases arrays are effectively handled differently than pointers. However, I cannot figure out what are the rules for assigning an array, or, in other words, why arrays inside a structure are copied when copying one structure to another, but I cannot directly copy one array to another.

+3


source to share


4 answers


There is no pointer in the structure, but 20 characters. After t2 = t1

20 characters are t1

copied to t2

.



+8


source


In C, a struct

is a way for the compiler to know how to structure a region of memory. A struct

is a kind of pattern or stencil that the C compiler uses to figure out how to compute offsets for various members of a structure.

The first C compilers did not allow assignment struct

, so people had to use a function memcpy()

to assign structures, but later compilers did. The C compiler will make the assignment struct

by copying the number of bytes of the memory area struct

, including padding bytes, that can be added to align addresses from one address to another. Everything that happens in the source area is copied to the destination area. Nothing has been done with the copy. It just copies so many bytes of data from one memory location to another.

If you have a string array in struct

or any kind of array, then the entire array will be copied as it is part of the structure.

If it struct

contains pointer variables, then those pointer variables will also be copied from one scope to another. The result of this is that you will have two structures with the same data. The pointer variables in each of these structures will have the same address values, with the two areas being copies of each other, so a particular pointer in one structure will have the same address as the corresponding pointer in the other structure, and both will point to in the same place ...

Remember that the purpose of a structure is simply to copy bytes of data from one area of ​​memory to another. For example, if we have a simple one struct

with an array char

with a C source similar to:

typedef struct {
    char tt[50];
} tt_struct;

void test (tt_struct *p)
{
    tt_struct jj = *p;

    tt_struct kk;

    kk = jj;
}

      



The assembler listing output by the Visual Studio 2005 C ++ compiler in debug mode for assignment kk = jj;

looks like this:

; 10   :    tt_struct kk;
; 11   : 
; 12   :    kk = jj;

  00037 b9 0c 00 00 00   mov     ecx, 12            ; 0000000cH
  0003c 8d 75 c4     lea     esi, DWORD PTR _jj$[ebp]
  0003f 8d 7d 88     lea     edi, DWORD PTR _kk$[ebp]
  00042 f3 a5        rep movsd
  00044 66 a5        movsw

      

This bit of code copies 4 byte word data into 4 byte words from one memory location to another. If the array size is smaller, the char

compiler may choose a different command to copy memory as more efficient.

C arrays are not really handled intelligently. An array is not considered a data structure in the same way that Java sees an array. In Java, an array is an object type made up of an array of objects. In C, an array is just a region of memory, and the array name is actually treated as a constant pointer, or a pointer that cannot be changed. As a result, you can have an array int myInts[5];

that Java will see as an array of five integers, but for C, which is actually a constant pointer with a labelmyInts

... In Java, if you are trying to access an element of an array out of range say myInts [i], where i is the value 8, you will get a runtime error. In C, if you are trying to access an out-of-range array element say myInts [i] where i is the value 8, you will not get a runtime error unless you are running a debug build with a good C compiler that does check execution. However, experienced C programmers tend to view arrays and pointers as similar constructs, although arrays as pointers have some limitations as they are a form of constant pointer and are not exactly pointers, but have some pointer-like characteristics.

This kind of buffer overflow error is very easy to do in C by accessing an array for its number of elements. A classic example is a string copy of a char array to another char array, and the original char array does not have a null termination character, resulting in a string copy of several hundred bytes when you expect ten or fifteen.

0


source


In your case, there are indeed 20 characters, this is the same as if you declared the structure as struct Test {char c1, char c2, ...}

If you only want to copy the pointer to the string, you can change the structure declaration as shown below and manually manage the memory for the string using the Test_init

and functions Test_delete

.

struct Test{
  char* str;
};

void Test_init(struct Test* test, size_t len) {
  test->str = malloc(len);
}

void Test_delete(struct Test* test) {
  free(test->str);
}

      

0


source


If you run the following simple program

#include <stdio.h>

int main( void )
{
    {
        struct Test
        {
            char str[20];
        };
        printf( "%zu\n", sizeof( Test ) );
    }

    {
        struct Test
        {
            char *str;
        };
        printf( "%zu\n", sizeof( Test ) );
    }
    return 0;
}

      

you will get a result similar to the following

20
4

      

So, the first structure contains a character array of 20 elements, and the second structure contains only a type pointer char *

.

When one structure is assigned to another structure, its data members are copied. Thus, for the first structure, the entire contents of the array are copied to another structure. For the second structure, only the pointer value (its address) is copied. The memory pointed to by the pointer is not copied because it is not contained in the structure itself.

And arrays are not pointers, although usually array names in expressions (with rare exceptions) are converted to pointers to their first elements.

0


source







All Articles