-3

Given a string (as the argument to function), after a given combination of characters, I need to delete the sequence of zeros, if exits(it only necessarily to modify the string). For example, if the combination of characters is x+, the string 20.301x+000005 must be converted to 20.301x+5.

I tried this:

void convertStr(char *analysisBuffer)
{
    char *exp;

    if( (exp = strstr(analysisBuffer,"x+"))!=NULL||(exp = strstr(analysisBuffer,"X+"))!= NULL)
    {
        exp += 2;
        char * zeroIt = exp;
        while(*zeroIt == '0')
            ++zeroIt;
        unsigned int x = exp - analysisBuffer;
        analysisBuffer[x] = '\0';
        strcat(analysisBuffer,zeroIt);
    }
}

Can anyone advise me how to implement it correctly?

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
YAKOVM
  • 9,805
  • 31
  • 116
  • 217
  • Did you mean `analysisBuffer[x] = '\0';` instead of `analysisBuffer[0] = '\0';`? – tdk001 Oct 04 '11 at 15:14
  • To restate your requirement: Delete all `0` that occur after a given sequence. Is it necessary to modify the string or is a copy allowed as well? – pmr Oct 04 '11 at 15:37

5 Answers5

3

This is a version that works for multiple occurences of the expression and reduces the size of the string so that no memory is occupied by zero terminators. This is probably slower and completely unnecessary but gives you the awesome feeling of doing something fancy.

Disclaimer: I haven't written any pure C in a long while.

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

char* strip_zero(char* str, const char* startseq) {
  // while there is an occurence of the substring
  size_t ssize = strlen(startseq);
  size_t oldlen = strlen(str) + 1; // account for terminator
  size_t rems = 0;
  char* begin = str;

  while((begin = strstr(begin, startseq))) {
    // move to the end of the sequence
    begin += ssize;
    char* walk = begin;
    // walk until we reach nonzero
    while(*walk == '0') { ++walk; ++rems; }
    // move the string forward
    memmove(begin, walk, strlen(walk) + 1);
  }

  // realloc the string
  return (char*)realloc(str, oldlen - rems);
}

int main(void)
{
  // make a copy so we can modify
  const char* a = "x+20.301x+00000x+0005x+";
  char* foo = (char*)malloc(strlen(a) + 1);
  strcpy(foo, a);
  printf("%s \n", foo);
  foo = strip_zero(foo, "x+");
  printf("%s \n", foo);
  free(foo);
  return 0;
}
pmr
  • 58,701
  • 10
  • 113
  • 156
  • +1 that's why I love C, for "the awesome feeling of doing something fancy" ;) – BlackBear Oct 04 '11 at 16:16
  • This doesn't solve the problem if the string has to be modified in place and I believe strcpy with overlapping strings may have undefined results. – Jim Rhodes Oct 04 '11 at 16:23
  • @Jim Thanks, I missed the "may not" part in the doc. I'll fix that. However I don't understand the second part of your comment. The modification is in-place. If the memory should be maintained you simply need to skip the `realloc` and everything will be alright. – pmr Oct 04 '11 at 16:27
  • @sarnold Sorry, my comment is confuse. By 'second part' I actually meant "doesn't solve the the problem ... in place". – pmr Oct 08 '11 at 13:58
  • @pmr, aha! I've removed my comments to decrease the overall clutter. Thanks :) – sarnold Oct 08 '11 at 23:32
2

Below is a more complete example of what you want. I tried to improve on a few items:

  • Use the strcasestr function for a case insensitive test. (We need the #define _GNU_SOURCE for this)
  • Use strcat (as you did) to append the tail of the string to the head.
  • Be careful to define the string as char test[] = "..." and not char *test = "...", as the latter will segfault.
  • There is an 'if' to see if we have to skip one ore more '0'.
  • You can get rid of the while loop, using a function like rindex(), which gives the right most index of a character in a string.

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

    void
convertStr(char *analysisBuffer)
{
    char *exp = strcasestr(analysisBuffer, "x+");

    if (exp) {
        exp += 2;
        if (*exp == '0') {
            while (*exp == '0') {
                *exp = '\0';
                exp++;
            }
            strcat(analysisBuffer, exp);
        }
    }
}

    int
main(int argc, char *argv[])
{
    char test[] = "20.301X+0005";

    printf("before: %s\n", test);
    convertStr(test);
    printf("after : %s\n", test);

    return EXIT_SUCCESS;
}
Johan
  • 3,072
  • 3
  • 27
  • 27
  • My C is rusty, but isn't modifying a string literal UB? Of course, to observe this is the obligation of the caller of your function but this is what your code does. – pmr Oct 04 '11 at 16:17
  • Yes, if it was a string literal, but I define a modifiable string array here. To fully answer your concern look at the following stackoverflow discussion: http://stackoverflow.com/questions/164194/why-does-simple-c-code-receive-segmentation-fault – Johan Oct 04 '11 at 19:51
  • Forgot to say I actually compiled and ran this code, so I know it works. I even tried some various inputs and used gdb to see if I encountered something odd. – Johan Oct 04 '11 at 19:55
1

Something like

char * write = str;
char * read = str;
while(*read){
    while(*read && *read == '0'){ read++; }
    *write++ = *read++;
}
*write = '\0';

? (this is untested)

hugomg
  • 68,213
  • 24
  • 160
  • 246
1

Instead of:

   unsigned int x = exp - analysisBuffer;
   analysisBuffer[x] = '\0';
   strcat(analysisBuffer,zeroIt);

you could just do:

   memmove(exp, zeroIt, strlen(zeroIt) + 1);
Jim Rhodes
  • 5,021
  • 4
  • 25
  • 38
1
size_t strip0( char *buff);
size_t strip0( char *buff)
{
size_t src,dst;

for (src=dst=0; buff[dst] = buff[src++] ;dst++ ) {
   if ((buff[dst] == 'x' || buff[dst] == 'X') && buff[src] == '+') {
      buff[++dst] = buff[src++] ;
      while (buff[src] == '0') src++;
      }
   }
return dst;
}

#include <stdio.h>

int main(int arc, char **argv)
{
char data[] = "100x+003 aap 200x+300 100X+003 noot 200X+300 mies 1234xX+000000000zzz";

printf("Org: %s\n", data);
strip0(data);
printf("New: %s\n", data);

return 0;
}
wildplasser
  • 43,142
  • 8
  • 66
  • 109