Search code examples
cstringcharc89concatenation

Cast char to char array or char array to char?


So let's say I have a char and I want to strcat() it to a char array in a single line of code. For [a non-practical] example:

strcat("ljsdflusdfg",getchar());

Or I wanted to do the reverse, what would be the appropriate function to concat or typecast strings, regardless of data type? Or perhaps there is some syntax I'm missing...

Here's an example. It compiles just fine but crashes.

char* input(){
 char* inp="";
 while(1){
  char c=getchar();
  if(c){
   if(c=='\n'||c==EOF){
    break;
   }else{
    strcat(inp,(char*)c);
   }
  }
 }
 return inp;
}

Solution

  • strcat treats its argument as a pointer to a nul-terminated string. Casting a char to a char * is just dangerous, and I can imagine no reason it would ever be useful (not to imply that you're stupid for trying it - everyone makes silly mistakes when they learn. That's why we're here.)

    The reason is that it would interpret the single byte char, plus the extra sizeof(char*) - sizeof(char) (usually 3) bytes surrounding that char, as a pointer, which would point to... anywhere. You have no way of knowing where it points, since 3 of those bytes are beyond your control, and thus no way of knowing whether it points to valid data.

    You might take this as a second approach:

    strcat(inp, &c);
    

    This time, you'd be doing better, since &c is an expression of type char * and no casts are required. But again, strcat assumes it's argument is a nul-terminated string, and since you have no way of guaranteeing a nul byte after your char data, this won't do.

    The best way is this:

    size_t len = strlen(inp); // this may already be calculated somewhere else
    ...
    inp[len++] = c; // add c as the last character, and adjust our len
    inp[len] = '\0'; // add a new nul terminator to our string
    

    UPDATE:

    Actually, I lied. The best way is to use the standard library function fgets, which appears to be doing more or less what you're trying to do. Truthfully I forgot it, but if this is a homework assignment your professor may not want you using fgets so that you can learn how to do it manually. However, if this isn't homework, fgets does exactly what you're looking for. (Actually, the third approach is well on its way to reimplementing fgets or fgets-like functionality.)

    I would also add some other commentary on your input function:

    1. char* inp = ""; will point to read-only data. A flaw in the C standard (for backwards compatability) allows string literals to be assigned to char* types instead of const char * types as it (IMHO) should be.

      There are several ways to approach this, but the best is dynamic allocation. Use the malloc function to reserve some data, keep track of how much you've used in your function, and use the realloc function if you end up needing more room to store it. If you need help with that, I'm sure you'll be back here (hopefully not too soon) with another question. :)
    2. getchar() returns an int, because EOF is defined to be outside the normal range of a char. In order to distinguish between any char and EOF, it's best to make c an int. Otherwise a perfectly valid character may signal EOF. Be sure to cast c down to a char when you add it to the string, though.