Michelle
Michelle

Reputation: 41

void function that removes al the non alphabet chars

I am trying to write a program that gets several strings until it gets the 'Q' string (this string basically stops the scanf). Each one of the strings is sent to a function that romoves everything except the letters. For example if I scan 'AJUYFEG78348' the printf should be 'AJUYFEG'. The problem is that the function has to be void. I have tried several ways to make the "new array with only letters" printed, but none of them worked. (Is is not allowed to use strlen function)

#include <stdio.h>

void RemoveNonAlphaBetChars(char*);

int main()
{
    int flag=1;
    char array[100]={0};
    while (flag == 1)
    {
        scanf("%s", &array);
        if(array[0] == 'Q' && array[1] =='\0') {
           flag=0;
        }
        while (flag == 1)
        {
           RemoveNonAlphaBetChars(array);
        }

    }

    return 0;
}

void RemoveNonAlphaBetChars(char* str)
{
    int i=0, j=0;
    char new_string[100]={0};

    for (i=0; i<100; i++)
    {
        if (((str[i] >= 'a') && (str[i] <= 'z')) || ((str[i] >= 'A') && (str[i] <= 'Z')))
        {
            new_string[j] = str[i];
            j++;
        }

    }
    printf("%s", new_string);
    return;
}

Upvotes: 1

Views: 239

Answers (3)

Mad Physicist
Mad Physicist

Reputation: 114478

The key here is that you are never inserting new characters into the string. That guarantees that the input buffer is large enough to hold the result. It also makes for an easy in-place solution, which is what the void return type is implying.

#include <ctype.h>
#include <stdio.h>
...

void RemoveNonAlphaBetChars(char* str)
{
    char *from, *to;

    for(from = to = str; *from; from++) {
        if(isalpha(*from)) {
            if(from > to) *to = *from;
            to++;
        }
    }
    *to = *from;
    printf("%s\n", str);
    return;
}

The pointer from steps along the string until it points to a NUL character, hence the simple condition in the loop. to only receives the value of from if it is a character. The final copy after the loop ensures NUL termination.

Update

If you are dealing with 1) particularly large strings, and 2) you have long stretches of letters with some numbers in between, and 3) your version of memmove is highly optimized compared to copying things manually (e.g. with a special processor instruction), you can do the following:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
...

void RemoveNonAlphaBetChars(char* str)
{
    char *from, *to, *end;
    size_t len;

    for(from = to = str; *from; from = end) {
        for(; *from && !isalpha(*from); from++) ;
        for(end = from; *end && isalpha(*end); end++) ;
        len = end - from;
        if(from > to) {
            if(len > 1) {
                memmove(to, from, len);
            } else {
                *to = *from;
            }
        }
        to += len;
    }
    *to = *end;
    printf("%s\n", str);
    return;
}

The general idea is to find the limits of each range of letters (between from and end), and copy into to block by block. As I stated before though, this version should not be used for the general case. It will only give you a boost when there is a huge amount of data that meets particular conditions.

Upvotes: 1

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140276

The fact that the function has only one argument, non-const char pointer, hints at the fact that the string is going to be changed in the call (better document it anyway), and it's perfectly all right.

A few fixes to your code can make it right:

First, don't loop to the end of the buffer, just to the end of the string (without strlen, it's probably faster too):

for (i=0; str[i] != '\0'; i++)

then don't forget to nul-terminate the new string after your processing:

new_string[j] = '\0';

Then, in the end (where you're printing the string) copy the new string into the old string. Since it's smaller, there's no risk:

strcpy(str,new_string);

now str contains the new stripped string.

Another approach would be to work in-place (without another buffer): each time you encounter a character to remove, copy the rest of the string at this position, and repeat. It can be inefficient if there are a lot of characters to remove, but uses less memory.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726929

void return type is a common approach to making functions that produce C string results. You have two approaches to designing your API:

  • Make a non-destructive API that takes output buffer and its length, or
  • Make an API that changes the the string in place.

The first approach would look like this:

void RemoveNonAlphaBetChars(const char* str, char *result, size_t resultSize) {
    ...
}

Use result in place of new_string, and make sure you do not go past resultSize. The call would look like this:

if (flag == 1) { // if (flag == 1), not while (flag == 1)
   char result[100];
   RemoveNonAlphaBetChars(array, result, 100);
   printf("%s\n", result);
}

If you decide to use the second approach, move printf into main, and use strcpy to copy the content of new_string back into str:

strcpy(str, new_string);

Upvotes: 0

Related Questions