0

I'm trying to replace ' ' (space) with '___' (triple underscore) in C.

Here is my code:

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

int main()
{
   char *a = "12 34 56";
   int a_l = strlen(a);
   printf("str1: \"%s\" (%d)\n", a, a_l);

   char *b = "___";
   int b_l = strlen(b);
   printf("str2: \"%s\" (%d)\n", b, b_l);

   for (int i = 0; i < a_l; i++) {
      if (a[i] == ' ') {
         char *o = malloc(a_l + b_l);

         strncpy(o, a, i);
         strncpy(o + i, b, a_l);
         //strncpy help

         printf("out:  \"%s\"\n", o);
      }
   }

   return 0;
}

I think that it is right so far, but I need to replace the comment line with correct strncpy (take the rest of string a (excluding space) and append it to string o). So the output should be like this:

str1: "12 34 56" (8)
str2: "___" (3)
out:  "12___34 56"
out:  "12 34___56"

If there are other mistakes in my code, please tell me.

UPD: This shouldn't replace all spaces in a loop. If the source string contains 8 spaces, there should be 8 lines printed and in each line only one space should be replaced.

4
  • Take a look at strtok function. Commented Jun 30, 2013 at 20:52
  • @V_Maenolis good idea, but as strtok() modifies the string, it won't work here on a which points to the literal/fixed "12 34 56". Commented Jun 30, 2013 at 20:53
  • 1
    In your code sample you make two o strings You ll have either to count first the space characters in your string then to allocate proper space to hold the new string or to realloc the o string for exery space you find. Commented Jun 30, 2013 at 20:59
  • Guys, you completely misunderstand what output should look like. All the answers are useful, but their aim is to replace everything in one loop. This code shouldn't replace all spaces with triple underscore. If the source string contains 8 spaces, there should be 8 lines printed and in each line only one space should be replaced. Commented Jul 1, 2013 at 5:36

6 Answers 6

6

You are overcomplicating this so much that I just TL;DR.

Some remarks that you might surely want to read, learn, embrace well and use:

I. int is not for string lengths and stuff. size_t is for string lengths and stuff.

II. String literals cannot be modified, so using the legacy char * type for assigning them to a variable is no good by any means, const-qualify that poor pointer base type.

III. Use VLAs instead of malloc() if dynamic memory management is not really needed (we're not living in 1989 anymore).

IV. NUL-terminate your strings because C stdlib routines expect you to do so.

int main()
{
    const char *in = "foo bar baz";
    int nspc = 0;

    for (const char *p = strchr(in, ' '); p; p = strchr(p + 1, ' '))
        nspc++;

    char buf[strlen(in) + nspc * 2 + 1];
    memset(buf, 0, sizeof(buf));

    const char *s = in;
    for (const char *p = strchr(s, ' '); p; p = strchr(s, ' ')) {
        strncat(buf, s, p - s);
        strcat(buf, "___");
        s = p + 1;
    }

    const char *end = in + strlen(in);
    strncat(buf, s, end - s);

    printf("%s\n", buf);
    return 0;
}
Sign up to request clarification or add additional context in comments.

7 Comments

Oh, and yes, this is seriously suboptimal (the loop runs over the input string twice, the repeated calls to strcat() make the concatenation run in O(n ^ 2) instead of O(n)), but until the strings are shorter than a few dozens of kilobytes, this "performance issue" is not really an issue at all. If you need to do so, benchmark and optimize it.
@RamyAlZuhouri Char-by-char? Surely I don't want that while we can haz stdlib functions from <string.h>. Seriously, that's your reason for the downvote?
@RamyAlZuhouri: Can it be done with a single loop while allocating memory only once?
@minitech I'm afraid not quite, except if one aims to do the exponential storage expansion trick, but I was too tired to implement that...
@minitech I think the downvoter hasn't considered that C is not Pascal, so strlen() loops through the string too.
|
2

You can try this one. The problem comes from the fact that a_l + b_l in your malloc is always the same value. It doesn't affect by number of spaces.

int count = 0, index = 0;
for (int i = 0;  i < a_l;  ++i) {
    if (a[i] == ' ') {
        count++;
    }
}

const char *o = malloc(a_l + 2 * count + 1); // 2 is because you add 3 new symbols, but remove 1 so 3 - 1 = 2
memset(o, 0, sizeof(o));

for (int i = 0;  i < a_l;  ++i) {
    if (a[i] != ' ')
        o[index++] = a[i];
    else {
        o[index++] = '_';
        o[index++] = '_';
        o[index++] = '_';
    }
}

2 Comments

Surely malloc() is not needed here since we stay inside main()... Also, where's the NUL-terminator?
Yes, you are completely right. I have missed NULL terminator and have used malloc, cos I was following the example code.
2

Without using library function!!!

while(*string)
        {
                  if(*string=='\\')
                {
                        *string++;
                        while(repl_len--)
                         *dest++ = *repl_string++;
                }               
                else
                {
                        *dest++ = *string++;
                }
           repl_string = temp_repl_string;
           repl_len = temp_repl_len;    
        }

Comments

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

size_t my_strlen(const char *str, size_t *spc){
    size_t len;
    *spc = len = 0;
    while(*str){
        ++len;
        if(*str++ == ' ')++*spc;
    }
    return len;
}

int main(void){
   char *a = "12 34 56";
   size_t spc;
   int a_l = my_strlen(a, &spc);
   printf("str1: \"%s\" (%d)\n", a, a_l);

   char *b = "___";
   int b_l = strlen(b);
   printf("str2: \"%s\" (%d)\n", b, b_l);

   char *p, *o = malloc(a_l - spc + spc * b_l + 1);
   p=o;
   for (int i = 0; i < a_l; i++) {
      if(a[i] == ' ') {
         strncpy(p, b, b_l);
         p += b_l;
      } else {
         *p++ = a[i];
      }
   }
   *p = '\0';
   printf("out:  \"%s\"\n", o);
   free(o);
   return 0;
}

3 Comments

why malloc()? Why int (instead of the correct size_t) for string lengths? Where's the const before pointers that ought to point to const char?
i don't know what are you saying.
@H2CO3 You are right, size_t should be used instead, although I think you are being a little paranoid, the use of size_t is no mandatory whatsoever. For example in my computer with an int I can hold up to 2GiB of data, IMO thats more than enough; unless you work at Google. It's all about Integer Overflow, IMHO with today's hardware this should not perturb you from sleeping at night. stackoverflow.com/questions/6004415/…
0

I see that many answers have been added, but this may have been done very simply with a single loop. Since the string is very short, you can sacrifice memory over CPU and allocate an array 3 times +1 bigger than the original string, and be sure that it won't be overflowed:

const char* string= "12 34 56";
size_t length= strlen(string);
char result[length*3 +1];
unsigned int index= 0;
memset(result, '\0', length*3+1);
for(int i=0; i<length; i++)
{
    if(string[i]!= ' ')
    {
        result[index++]= string[i];
    }
    else
    {
        strcat(result,"___");
        index+= 3;
    }
}

Comments

0

I found another thread and after reading the answers, I figured out that the right line should look like this:

strncpy(o + i + b_l, a + i + 1, a_l - i);

And after few fixes that were suggested in this thread my code looks like this:

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

int main()
{
   char *a = "12 34 56";
   size_t a_l = strlen(a);
   printf("str1: \"%s\" (%d)\n", a, a_l);

   char *b = "___";
   size_t b_l = strlen(b);
   printf("str2: \"%s\" (%d)\n", b, b_l);

   for (int i = 0; i < a_l; i++) {
      if (a[i] == ' ') {
         char *o = malloc(a_l + b_l);

         strncpy(o, a, i);
         strcpy(o + i, b);
         strncpy(o + i + b_l, a + i + 1, a_l - i);

         printf("out:  \"%s\"\n", o);
             free(o);
      }
   }

   return 0;
}

And this prints the desired putput.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.