2

I have a variable length string that I am trying to divide from plus signs and study on:

            char string[] = "var1+vari2+varia3";
            for (int i = 0; i != sizeof(string); i++) {               
                memcpy(buf, string[0], 4);
                buf[9] = '\0';
            }

since variables are different in size I am trying to write something that is going to take string into loop and extract (divide) variables. Any suggestions ? I am expecting result such as:

var1
vari2
varia3
chqrlie
  • 131,814
  • 10
  • 121
  • 189
servedc0ld
  • 49
  • 5
  • 3
    What's wrong with a loop that looks for the `+` character? Or use a standard lib function like [strtok](https://man7.org/linux/man-pages/man3/strtok.3.html) – kaylum Aug 18 '20 at 00:13
  • 2
    Also, using `string[0]` in `memcpy` is very wrong and your compiler should have warned you about that. It should be `string`. – kaylum Aug 18 '20 at 00:15

4 Answers4

2

You can use strtok() to break the string by delimiter

   char string[]="var1+vari2+varia3";
   const char delim[] = "+";
   char *token;
   
   /* get the first token */
   token = strtok(string, delim);
   
   /* walk through other tokens */
   while( token != NULL ) {
      printf( " %s\n", token );
    
      token = strtok(NULL, delim);
   }

More info about the strtok() here: https://man7.org/linux/man-pages/man3/strtok.3.html

1

You can use a simple loop scanning the string for + signs:

    char string[] = "var1+vari2+varia3";
    char buf[sizeof(string)];
    int start = 0;
    for (int i = 0;;) {
        if (string[i] == '+' || string[i] == '\0') {
            memcpy(buf, string + start, i - start);
            buf[i - start] = '\0';
            // buf contains the substring, use it as a C string
            printf("%s\n", buf);
            if (string[i] == '\0')
                break;
            start = ++i;
        } else {
            i++;
        }
    }
        
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

It seems to me that you don't just want to want to print the individual strings but want to save the individual strings in some buffer.

Since you can't know the number of strings nor the length of the individual string, you should allocate memory dynamic, i.e. use functions like realloc, calloc and malloc.

It can be implemented in several ways. Below is one example. To keep the example simple, it's not performance optimized in anyway.

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

char** split_string(const char* string, const char* token, int* num)
{
    assert(string != NULL);
    assert(token != NULL);
    assert(num != NULL);
    assert(strlen(token) != 0);

    char** data = NULL;
    int num_strings = 0;
    while(*string)
    {
       // Allocate memory for one more string pointer
       char** ptemp = realloc(data, (num_strings + 1) * sizeof *data);
       if (ptemp == NULL) exit(1);
       data = ptemp;
       
       // Look for token
       char* tmp = strstr(string, token);
       
       if (tmp == NULL) 
       {
           // Last string
           // Allocate memory for one more string and copy it
           int len = strlen(string);
           data[num_strings] = calloc(len + 1, 1);
           if (data[num_strings] == NULL) exit(1);
           memcpy(data[num_strings], string, len);

           ++num_strings;    
           
           break;
       }
       
       // Allocate memory for one more string and copy it
       int len = tmp - string;
       data[num_strings] = calloc(len + 1, 1);
       if (data[num_strings] == NULL) exit(1);
       memcpy(data[num_strings], string, len);
       
       // Prepare to search for next string
       ++num_strings;
       string = tmp + strlen(token);
    }
    
    *num = num_strings;
    return data;
}

int main()
{
    char string[]="var1+vari2+varia3";
    
    // Split the string into dynamic allocated memory
    int num_strings;    
    char** data = split_string(string, "+", &num_strings);

    // Now data can be used as an array-of-strings
    
    // Example: Print the strings
    printf("Found %d strings:\n", num_strings);
    for(int i = 0; i < num_strings; ++i) printf("%s\n", data[i]);
    
    // Free the memory
    for(int i = 0; i < num_strings; ++i) free(data[i]);
    free(data);

}

Output

Found 3 strings:
var1
vari2
varia3
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • @chqrlie I'm sure you got a good point but I'm not sure I fully understand your comment. Is it input examples? If so I don't understand as `"+"` will give **one** empty string - not two – Support Ukraine Aug 18 '20 at 20:55
  • Another corner case is if `token` is an empty string. `split_string()` runs an infinite loop in this case. – chqrlie Aug 18 '20 at 21:04
  • @chqrlie The intention is that `""` gives zero strings, `"+"` gives one empty string. `"++"` gives two empty strings. In other words – Support Ukraine Aug 18 '20 at 21:05
  • Indeed a trailing `+` does not cause a trailing empty string to be produced. I am not sure is this is correct since an initial `"+"` does produce an initial empty string. – chqrlie Aug 18 '20 at 21:06
  • @chqrlie yep, an empty token... that's a mistake. I should check for that (or just say that calling with an empty token is UB :) – Support Ukraine Aug 18 '20 at 21:06
  • @chqrlie Well, I designed it like that, i.e. the last `+` doesn't give an empty string in the end. Whether that is what OP wants is not clear. – Support Ukraine Aug 18 '20 at 21:08
  • OK. design decision is fine. Corner cases are always tricky. For example: `strtok()`, which has it own can of problems, cannot produce empty tokens. Any sequence of separator characters is considered a single separator, which is probably OK for whitespace but highly questionable for `+`. – chqrlie Aug 18 '20 at 21:09
  • regarding: `if (ptemp == NULL) exit(1);` this results in the very memory leak that you were trying to avoid. so does: `if (data[num_strings] == NULL) exit(1);` – user3629249 Aug 19 '20 at 15:11
  • @user3629249 On all modern hosted environments the memory will be free'ed when your program exit. Whether or not is better to do it your self or let the environment handled it for you, is something that you can find very different opinions about. – Support Ukraine Aug 19 '20 at 15:28
  • @4386427, not closing files, not freeing memory, etc WILL bite the programmer, especially when they write embedded code. It is best to properly cleanup before exiting an application. Not doing so is a sign of a very sloppy programmer that I (and most hiring managers) would not want in my organization. – user3629249 Aug 19 '20 at 16:06
0

Your code does not have any sense.

I wrote such a function for you. Analyse it as sometimes is good to have some code as a base

char *substr(const char *str, char *buff, const size_t start, const size_t len)
{
    size_t srcLen;
    char *result = buff;

    if(str && buff)
    {
        if(*str)
        {
            srcLen = strlen(str);
            if(srcLen < start + len)
            {
                if(start < srcLen) strcpy(buff, str + start);
                else buff[0] = 0;          
            }
            else
            {
                memcpy(buff, str + start, len);
                buff[len] = 0;
            }
        }
        else
        {
            buff[0] = 0;
        }
    }
    return result;
}

https://godbolt.org/z/GjMEqx

0___________
  • 60,014
  • 4
  • 34
  • 74