note: This is work in progress, and I’d love some critical feedback.

After analysing my Google sources, I’ve noticed people asking questions to Google that I haven’t answered. I figured I’d give it a shot. This question is a good one, but I may need to go back and fill in some gaps. (It’s been a while since I posted here…).

Before I answer this question, there are a few basic guidelines that should be covered.

  • Watch the types! When an argument is a void pointer (void *), C will implicitly convert any pointer-to-object type you like (eg. char *, int *, struct fortytwo *), but this can bite you. Let us consider parity (checksum) bits when copying unsigned int foo = 0xBEEF; to an int bar;… Can anyone spell “segfault”?
  • Watch the length! I’m sure I don’t have to tell you, a scholar studying C, not to overflow buffers! For the same reason that you should ensure your code does not write out of bounds of an array or object, you should ensure your code does not read out of bounds of an array or object. Likewise, always ensure you give your objects values before you access them; Accessing an uninitialised object is also undefined behaviour.
  • Copy from one object into another. Don’t use the same array or object as both the source and the destination; memcpy isn’t good at that. If the source and destination overlaps, the behaviour is undefined. Use memmove for that, instead. The usage is exactly the same.

Now that we’ve covered the safety material, let us move on to creating objects. There are two ways to create objects in C. The first, you probably already know about, is the easiest…

Declare a variable. If you’re only copying one value (eg. not an array), then there is no need to use memcpy; Just use the assignment operator! memcpy is most useful for copying arrays. Below I have declared three arrays. The first two I have initialised to store strings.

char foo[] = "hello";
char bar[] = "world";

I’ll be demonstrating a concatenation (join operation) on these strings. There are just a few things to note, first.

  • foo is an array of 6 chars. The 6 chars in that string are ‘h’, ‘e’, ‘l’, ‘l’, ‘o’ and the string terminator, ‘\0′. bar is also an array of 6 chars. There is no surprise here.
  • Both foo and bar have well defined values. I can access the following six items safely: foo[0], foo[1], foo[2], foo[3], foo[4] and foo[5]. The same goes for bar.
  • Neither foo nor bar have enough space to store the resulting concatenation; strcat(foo, bar) is undefined behaviour because strcat will copy bar onto the end of foo and there isn’t enough space in foo… Out of the question (this is a jab at Mark Lassoff because he’s too self-righteous to fix his errors).

char foobar[sizeof foo + sizeof bar]; // foobar is an array large enough to hold the characters from “hello” and “world”, including the two lots of string terminators. foobar is required because neither foo nor bar are large enough to store the result of the concatenation; I needed to declare something large enough.

memcpy(foobar, foo, sizeof foo); // This should seem fairly obvious to the average student studying C: It copies the characters within foo (“hello”) into foobar. There are a few things happening behind the scenes here, however… The first two arguments are arrays, but they’re being converted to pointers before they’re passed to memcpy. There is an implicit conversion there between char[6] and char *, and another one between char * and the type that malloc expects for those arguments: void *.

char *temp = foobar + sizeof foo; // temp now points to the foobar[6]. To those who have studied arrays briefly, having this line probably seems silly or confusing. However, there is more to it than meets the eye. [] is not an array operator; it is actually a pointer operator. Within the above memcpy code, there are two implicit conversions going on behind the scenes. The same implicit conversion happens to foobar when you access foobar[0], foobar[1], etc. foobar[0] is the same as *(foobar). Thus, *temp is the same as temp[0]. Because temp == foobar + sizeof foo, the following is also true: temp[0] == foobar[sizeof foo].

temp[-1] = ‘ ‘; // Prior to this statement, temp[-1] was the string terminator for “hello”, right? I didn’t think it’d be suitable to paste “world” straight onto the end without a space in between ;)

memcpy(&temp[0], bar, sizeof bar); // This notation may seem more familiar than the pointer arithmetic I used above. It is the alternative to memcpy(temp + 0, bar, sizeof bar);. Pointer arithmetic is a very important aspect of C, and I may have to fill in some blanks later on.

This concludes this post. Hopefully I’ve managed to answer the question one unlucky Googler posed, while exploring some other interesting concepts within C. If you got to the pointer arithmetic section of this post before you were confused, read the entire blog post again and let me know precisely what it is that boggles your mind ;)

(… to be continued…)

© 2011 GeekyCode proudly hosted by GeekShells. Suffusion theme by Sayontan Sinha