Archive

Archive for February, 2009

C Tidbit: Arrays of Strings as char**

February 22nd, 2009

While working further on my crypto assignment this evening, I had a hell of a time working with an array of strings in C. For those of you who know C, a string is really a character pointer (char *), and an array of strings, while often denoted *str[], can also be allocated as a pointer to a pointer of chars (char **). Long story short, after writing a bunch of code that utilizes this, I realized that I didn’t need all those strings and could actually get by with just one temporary variable, so I rewrote my code and got rid of all the code that took me so long to figure out. Because what I learned was useful, I’m writing it here for posterity and hopefully as a decent explanation for anyone else. This isn’t all the code that I wrote, but just snippets big enough to get the gist.

So, when you want to allocate memory for a bunch of (related) strings, you have two choices:

  1. Declare one char pointer (char *) and allocate enough memory for all the strings (and their terminating NUL bytes).
  2. Declare a pointer to a char pointer (char **) and allocate memory for the pointers and strings themselves separately.

My problems arose when I tried to combine these two approaches, by using a char** so I could access my individual strings with array notation (str[i]), but since I knew how much space I’d need ahead of time (but not at compile time), allocating all the memory at once. It makes sense that this didn’t work, since I was actually allocating a lot of space for a ton of pointers, but not actually any memory for the character pointers (i.e. the strings).

Since my explanation is mediocre, here’s a bit of code to explain:

/* Approach 1: one big char pointer */
char *bigstr; // Declare one character pointer, i.e. one string
int length = 72; // Enough space for 8 8-char values plus a NUL byte for each
int i;


bigstr = malloc(sizeof(char) * length);
for (i = 0; i < length; i += 9) { // I know this sucks, and I later fixed it
    fscanf (infile, "%s", &input_strs[i]);
    // or fscanf(infile, "%s", input_strs + i);
}

So, the benefit of the above approach is that you can allocate your memory all at once. The downside is that you have to either access the input_strs[] with the address-of operator (the ampersand) or just shove the pointer in and do pointer arithmetic.

Now, on to the second option:

/* Approach 2: pointer to a pointer */
char **str_array; // Declare a pointer to a pointer, i.e. an array of strings
int length = 8; // Enough space for 8 char pointers
int input_str_size = 9; // Enough space for 8 bytes plus NUL
int i;


str_array = malloc(sizeof(char *) * length);
for (i = 0; i < length; i++) {
    str_array[i] = malloc(input_str_size);
    fscanf (infile, "%s", str_array[i]);
    // or fscanf(infile, "%s", *input_strs + i);
}

The advantage of this second approach, as you can see, is that you can directly apply the array notation without the (possibly confusing) need for the address-of operator. The downside is that you don’t allocate all the memory ahead of time, so it may be slower to allocate small chunks of memory in a loop. This would be the way to go, however, if your strings were of different sizes.

Which of these two paths you choose is up to you, and it really depends on your application. However, just remember the difference between the two, and try not to mix them up like I did!

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • Technorati

programming ,

C Tidbit: Reading in “binary” from text file with strtol

February 22nd, 2009

Last night, I was working on an assignment for my cryptography class (writing SPN and Feistel ciphers in C), and I was looking for a way to read in “binary” from a text file. I.e. the file itself was not a binary file, but rather I was reading ASCII 0 and 1 characters from the file and interpreting them in my program. After a bit of searching, I came across the man page for atoi, which states that its behavior is the same as:

strtol(nptr, (char **) NULL, 10);

I’ve never seen this “strtol” before, so I went and looked at its man page, and it turns out that this is the magic function that let me do what I wanted to do. That last argument is the numerical base, so I just do something like so:

long int myint = strtol(binary_str, NULL, 2);

Of course, this is after reading in a series of binary strings as character pointers from the file with fscanf. I.e. in the above, binary_str is a char * that contains something like “01101001″.

I just thought this was worth sharing, since without knowing about this function, anyone trying to do this has to end up writing annoying binary/decimal conversion functions. Not particularly difficult, but annoying nonetheless when the functionality is right there.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • Technorati

programming ,

/etc/mtab Boot Nightmare

February 20th, 2009

The other day, I was working on my senior design project (a kernel project), and I did the good ol’ make/make install/reboot to see my changes. Coming back, expecting my computer to have booted, I found it hung at:

Cannot create link /etc/mtab
perhaps there is a stale lockfile?

Naturally thinking it was my project’s fault (it was), I rebooted into my normal kernel. To my horror, the same error came up. After a period of mini-panic, I ran to Google and at the same time reached for my Gentoo CD (the newest I could find was 2007.0 minimal, but it still works!). I ran e2fsck on both my home and root partitions for good measure, and then mounted my root partition and looked at /etc/mtab*. Apparently, the fact that there was mtab, mtab~, mtab~2205 and mtab~2213 isn’t normal. On recommendation from this obscure post from three years ago, I deleted the extra files (after examining them and noting they were not only extraneous but empty), rebooted, and viola! Problem solved!

Turns out a number of different things I did caused this error several different times. Not exactly sure why, but it always seems to coincide with the boot of or boot after a kernel oops or panic.

External Links

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • Technorati

linux ,