views:

180

answers:

4

Hi,

I wrote this function:

void r_tabs_spaces(char *input) {
       int  i;
       for (i = 0; i < strlen(input); i++)
       {
        if (input[i] == ' ' || input[i] == '\t')
                 input[i] = '';
       }
}

However when I compile this and run it, the compiler complains that "error: empty character constant" at line where I try to input[i] = '';

How can I do this in C then?

+1  A: 

The way to remove a character of a string is to move the rest of the string one character back.

AProgrammer
+8  A: 

In C, a string is an array of bytes. You can't assign an "empty byte", but you have to shift the remainder of the bytes forward.

Here's one way of how to do that:

char *write = str, *read = str;
do {
   // Skip space and tab
   if (*read != ' ' && *read != '\t')
       *(write++) = *read;
} while (*(read++));

Remember that literal strings in C are usually in write-protected memory, so you have to copy to the heap before you can change them. For example, this usually segfaults:

char *str = "hello world!"; // Literal string
str[0] = 'H'; // Segfault

You can copy a string to the heap with strdup (among others):

char *str = strdup("hello world!"); // Copy string to heap
str[0] = 'H'; // Works

EDIT: Per your comment, you can skip only initial whitespace by remembering the fact that you've seen a non-whitespace character. For example:

char *write = str, *read = str;
do {
   // Skip space and tab if we haven't copied anything yet
   if (write != str || (*read != ' ' && *read != '\t')) {       
       *(write++) = *read;
   }
} while (*(read++));
Andomar
... and don't forget to take care of the remaining tail bytes. If they are allocated dynamically, release them.
Dmitry
Oh, I forgot to add one thing. I need to remove only the leading spaces and tabs but if a string has them between the characters then I need to leave them as they are. They above solution works fine but it removes all of them. How can I leave the ones that are between characters?
goe
That's great, thanks
goe
Don't forget that `<ctype.h>` defines useful macros, and break can exit loops early.
Jonathan Leffler
Also, for the revised definition of the problem, you could probably just loop over the leading blanks and tabs, then use `memmove()` to copy the data from the first non-blank, non-tab up to the end over the start of the string. And use `memmove()` not `memcpy()` because the memory overlaps.
Jonathan Leffler
@Jonathan Leffler: You can even skip the `memmove()` as pmg's answer shows:)
Andomar
+1  A: 

If you have a pointer to the string

"            string with leading spaces"
 ^ pointer

just move it ...

"            string with leading spaces"
             ^ pointer

for example:

#include <ctype.h>
/* ... */
char mystring[] = "            string with leading spaces";
char *pointer = mystring;
while (*pointer && isspace((unsigned char)*pointer)) ++pointer;
/* pointer now points to a (possibly empty) string with no leading spaces */
pmg
+1 Doesn't even require the string to be on the heap :)
Andomar
A: 

Use

foo += strspn(foo, " \t");

to move the pointer foo to the first character which is not a space or tab.

To actually remove the characters from a dynamically allocated string, use

size_t offset = strspn(foo, " \t");
size_t size = strlen(foo + offset) + 1;
foo = realloc(memmove(foo, foo + offset, size), size);
Christoph