Differences

This shows you the differences between two versions of the page.

Link to this comparison view

c [2014/04/11 21:41] (current)
beandog created
Line 1: Line 1:
 +====== C ======
  
 +==== Strings ====
 +
 +This took me forever to figure out, so I'm putting it here so it doesn'​t get lost. :)
 +
 +<code c>
 +#include <​stdio.h>​
 +#include <​string.h>​
 +
 +int main() {
 +
 + // References:
 + // http://​www.programiz.com/​c-programming/​c-strings
 + // http://​www.c-faq.com/​charstring/​index.html
 + // http://​www.c-faq.com/​charstring/​assign.html
 +
 + // STRINGS ARE ARRAYS OF CHARACTERS *WITH* A NULL TERMINATOR
 + // Remember that, because that makes sense when you try to copy strings
 + // from one place to another. ​ It becomes much clearer when you realize
 + // you're only dealing with *arrays*.
 + //
 + // Consider an example in PHP:
 + // $arr_chars() = array();
 + // You can't say $arr_chars = '​hello';​ because they aren't even the
 + // same type.  You could however say:
 + // $arr_chars = array('​H',​ '​e',​ '​l',​ '​l',​ '​o'​); ​ This example also
 + // illustrates the length of each value in an array -- one character.
 + //
 + // A STRING, then, it just an array of characters with a NULL
 + // terminator as the last value.
 + //
 + // In the same example, $arr_chars has 5 values: one for each letter.
 + // However, in C, a "​string"​ needs to have a NULL terminator. ​ So
 + // if using the same PHP syntax, the new array would look like this:
 + // $arr_chars = array('​H',​ '​e',​ '​l',​ '​l',​ '​o',​ '​\0'​);​ and it has
 + // six values again.
 + //
 + // When copying strings around, remember that you only want parts of
 + // the array. ​ You can initialize an array, and have a null terminator,
 + // which makes it a string, but that is still not the END of possible
 + // values in the array. ​ You would still need to resize it to the
 + // correct size.
 + //
 + // So, for example, using PHP syntax as an example, let's say you
 + // wanted to create an array of 6 characters ('​Hello\0'​) and create
 + // a new one with only the first two *string* characters ('​He'​).
 + //
 + // The size of the first array needs to b 6 -- 5 characters and one
 + // null terminator.
 + //
 + // Creating a string like this automatically adds the terminator:
 + char *hello = "​Hello";​
 + // Likewise, create a new array with a specific number of characters:
 + // two, plus one for the null terminator.
 + char hi[3];
 + // Use the strncpy function to copy *contents of the array* from one
 + // to another.
 + //
 + // strncpy() is a good function for two main reasons:
 + // 1. It allows you to set a fixed amount of characters (array
 + //    elements). ​ This is a good feature because it limits the
 + //    amount you want to copy.
 + //
 + //    I was trying to think of a good example to use of why this is
 + //    helplful, but I couldn'​t really come up with anyhting, mostly
 + //    because it's this second feature that really makes it shine:
 + //
 + // 2. It automatically adds a null terminator **if** the size of the
 + //    source is at least one smaller than the destination. ​ This is
 + //    where the real power of this function comes into play.  Since
 + //    it's used for strings, who need null terminators,​ it simply
 + //    takes care of managing one for you.
 + //
 + // Here are some specific walkthroughs. ​ First, let's start with two
 + // words that we can trim down and they'​ll both be full words. ​ Let's
 + // use "​hope"​ and "​hop"​. ​ Since they are only one character apart, that
 + // will make it simpler.
 + //
 + // Create the first string. ​ It will be an array of characters with
 + // four of them being letters, and the fifth a null terminator.
 + //
 + // For the sake of verbosity, we'll set each value directly.
 + char str[5] = {'​H','​o','​p','​e','​\0'​};​
 + //
 + // If we check the string length, then it will return 4.  The strlen
 + // function counts all the letters *up until* the null terminator. So
 + // even though the array has 5 characters, there are only 4 actual
 + // lettters.
 + printf("​string length: %lu\n",​ strlen(str));​
 + //
 + // At the same time, if we looked at the *real* size of the array, it
 + // will say that there are 5 characters.
 + printf("​sizeof array: %lu\n",​ sizeof(str));​
 + //
 + // Once you understand that, you can see how strings are really just
 + // a quick check to see if there'​s a null terminator or not.
 + //
 + // That's it!  Pretty simple when you look at it that way.  The
 + // string length is always one less than the size of the actual array.
 + //
 + // Now, some IMPORTANT THINGS TO REMEMBER about strncpy():
 + //
 + // 1. "​Warning: ​ If  there  is no null byte among the first n bytes of
 + //    src, the string placed in dest will not be null-terminated."​
 + //
 + // You don't really have to worry about this if your source array
 + // wasn't a string anyway, because you'd probably know what you were
 + // doing anyway.
 + //
 + // An example:
 + char abc[3] = {'​a','​b','​c'​};​
 + // Is this a string? ​ No, it is not, because it doesn'​t have a null
 + // terminator on the end.  It's an array with three characters. ​ Now
 + // if you want to copy that array to another one of the same size, then
 + // you can use strncpy. ​ But since there'​s no null terminator, it won't
 + // gracefully add one for you, because you didn't set that expectation
 + // in the first place;
 + //
 + // Moving on, create a second array with 3 possible values.
 + char abc_clone[3];​
 + // And use strncpy to copy the original in to the new one:
 + strncpy(abc_clone,​ abc, 3);
 + // There'​s no null terminator added here, so checking the size will
 + // return a 3.
 + printf("​sizeof abc_clone: %lu\n",​ sizeof(abc_clone));​
 + //
 + // Now let's do the same thing, but this time with a string.
 + char str_abc[4] = {'​a','​b','​c','​\0'​};​
 + // This array has a null terminator plus three characters, so it counts
 + // as a string. ​ Let's use strncpy again to copy it directly to another
 + // string:
 + char str_abc_clone[4];​
 + strncpy(str_abc_clone,​ str_abc, 4);
 + // Strangely enough, strncpy isn't doing anything special here, because
 + // it's copying all the array values. ​ Having a null terminator on the
 + // source doesn'​t make a difference to the destination,​ because all
 + // four values are being copied anyway.
 + //
 + // To show some of the power of strncpy, we'll create an array with
 + // one more additional value, and then compare sizes after using strncpy.
 + //
 + // Here, we set another array:
 + char five_ton[5];​
 + // If we checked the size of the array, it would return 5 -- just as
 + // expected, because that is how we declared it.
 + //
 + // Now, what happens when you take a string (three letters + one null
 + // terminator) and add it to an array that is larger than it?
 + //
 + // First, let's go ahead and copy ALL the characters that the first array
 + // has, including its null terminator:
 + strncpy(five_ton,​ str_abc, 4);
 + // Remember that '​str_abc'​ is an array of four characters (three letters
 + // plus one null terminator). ​ The *size* of the array of five_ton has
 + // not changed at all -- it's still five characters:
 + printf("​size of five_ton: %lu\n",​ sizeof(five_ton));​
 + // However, if we checked the length of the string, it's going to stop
 + // at the first null terminator, so it will say it is 3 instead of 5.
 + printf("​string length of five_ton: %lu\n",​ strlen(five_ton));​
 + //
 + // In that first example, we told strncpy to pass FOUR of the FOUR
 + // characters in our '​abc'​ string, which also put the null terminator
 + // in there, because it was a part of that array.
 + //
 + // This is where the magic of strncpy comes into play -- if you only
 + // passed those *three* letters, and the new array can hold the original
 + // size (three) plus one more, it will automatically add a null
 + // terminator for you -- thus making strncpy essentially a "copy from
 + // an array to a string"​ function. :)
 + //
 + // Here's another example:
 + char five_more_tons[5];​
 + strncpy(five_more_tons,​ str_abc, 3);
 + // Now the size of the array is still going to be 5, because that's
 + // how many characters we set it to (allocated memory for).  The string
 + // length, however, is only going to be 3 -- the same string length
 + // of the '​str_abc'​ array. ​ You can again verify it using sizeof() and
 + // strlen():
 + printf("​size of five_more_tons:​ %lu\n",​ sizeof(five_more_tons));​
 + printf("​string length of five_more_tons:​ %lu\n",​ strlen(five_more_tons));​
 +
 + // That's it for now!! There'​s still a lot of questions I have, such as:
 + // - How do you "​trim"​ a string -- make the size of the array smaller?
 + //   Seems to me that maybe making a new array is easiest, and using
 + //   ​strlen() to get the total size, plus one, and then strncpy() to
 + //   put it in there. ​ Example?
 + char fun[16];
 + fun[0] = '​f';​
 + fun[1] = '​u';​
 + fun[2] = '​n';​
 + fun[3] = '​\0';​
 + // The array length is still 16, and has 12 more characters it can hold.
 + // Get the array size of the new one -- the length of the string, plus
 + // an extra one for the null character:
 + int i = strlen(fun) + 1;
 + char less_fun[i];​
 + // Then go ahead and strncpy like normal!
 + // Since the first array has a null terminator already, and the second
 + // array has room for it, then *either* one of these strncpy functions
 + // would work, and return the same result:
 + //
 + // strncpy adds its own null terminator:
 + strncpy(less_fun,​ fun, 3);
 + // strncpy copies all the characters, including the null terminator:
 + strncpy(less_fun,​ fun, 4);
 + // That's still not a real "​fix"​ to shortening a string, but it does
 + // make it possible to just start over.  Is there a way to make it go
 + // a little faster? ​ That is, in less code ..
 + char str_testing[strlen("​testing"​) + 1];
 + strncpy(str_testing,​ "​testing",​ strlen("​testing"​));​
 + printf("​testing:​ %s\n", str_testing);​
 + // ... or in that case, just more complex.
 +
 +}
 +</​code>​

Navigation