Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

I do I eliminate the 2 strlens from this?

  1. Jun 17, 2015 #1
    I have a chunk of code that is like

    Code (Text):

      if (rt->op) // if rt is of the form rt = gx op hx
      {
      char * dgdx = deriveFromTree(rt->gx); // g'(x)
      char * dhdx = deriveFromTree(rt->hx); // h'(x)
      char thisop = *rt->op;
      if (thisop == '+' || thisop == '-')
        {
          //  ADDITION/SUBTRACTION RULE:
         //  dfdx = dgdx + thisop + dhdx
          long n = strlen(dgdx) + strlen(dhdx) + 2;
          dfdx = malloc(sizeof(char) * n); dfdx[n-1]='\0';
          dfdx = strcat(dfdx, dgdx);
          dfdx = strcat(dfdx, charToString(thisop));
          dfdx = strcat(dfdx, dhdx);
         }
     
    and I want to do it without the strlen(dgdx) and strlen(dhdx) because they seem redundant considering that the implementation of strcat iterates over all the characters of the string again. How do I redo this overall crappy procedure?
     
  2. jcsd
  3. Jun 17, 2015 #2
    So you're trying to just add or subtract two numbers by trying to incorporate the operation into a string, that takes up the appropriate amount of memory as defined by the numbers and the operation, so then you can solve it im guessing? Or whats the end goal of this supposed to be? There are also vastly better, infinitely easier languages to do this in then C.

    I suppose you could always rewrite your own strcat function that takes a character (for the operation) and two character pointers to count how many characters are in the string and then use malloc from that result, which would let avoid calling strlen twice and enable you to only have to call modified strcat once making your code much cleaner and more efficient. But does that small amount of efficiency really even matter? Are you writing for a microcontroller or a mega database or something?
     
  4. Jun 17, 2015 #3

    Svein

    User Avatar
    Science Advisor

    How about a very short expression to do everything below // ADDITION...? (except the malloc part)

    n = sprintf(dfdx, "%s %c %s", dgdx, thisop, dhdx);
     
  5. Jun 17, 2015 #4

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    An alternative is to use C++ and std::string rather than C and C-style strings. Then you can just add the strings, using the "+" operator:

    Code (C):

    std::string dgdx = deriveFromTree(rt.gx); // g'(x)
    std::string dhdx = deriveFromTree(rt.hx); // h'(x)
    std::string dfdx;
    if (rt.op == '+' || rt.op == '-')
    {
        //  ADDITION/SUBTRACTION RULE:
        dfdx = dgdx + rt.op + dhdx;
    }

     
     
  6. Jun 17, 2015 #5
    The point is to make things harder
     
  7. Jun 17, 2015 #6
    That greatly helps make my procedure more compact, but I still need a way to know how large to make buffer dfdx.
     
  8. Jun 17, 2015 #7

    Mark44

    Staff: Mentor

    There was a long thread recently about the advantages of making code more compact (https://www.physicsforums.com/threads/code-readability-for-higher-level-languages.816168/). The upshot was that there really isn't much advantage in making the source code more compact, especially if it makes the code more opaque to the reader.
    I don't see the calls to strlen() being redundant, as you say. You need to know the lengths of the two strings that you are going to concatenate. The fact that strcat copies character-by-character doesn't obviate the need to know how large the buffer for dfdx needs to be.
     
  9. Jun 17, 2015 #8

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    There is little point in doing that in professional programming. A major aspect of professional programming is making things easier. From other threads, you are an aspiring C++ programmer. If that's still the case, you should stop thinking like a C programmer, or like a Java programmer. Well-written C++ has zero calls to malloc and free, and very few calls to new and delete.

    Given that, ...
    Unlike many other languages, C-style strings don't store the length as a separate property. That coupled with the need to allocate storage means there's no way around calling strlen twice for this problem. There is however something you can do since you know the lengths of the strings:
    Code (C):

    char * dgdx = deriveFromTree(rt->gx); // g'(x)
    char * dhdx = deriveFromTree(rt->hx); // h'(x)
    char thisop = *rt->op;
    std::size_t dgdx_len = std::strlen(dgdx);  // Omit std:: if you are using C.
    std::size_t dhdx_len = std::strlen(dhdx);
    char *dfdx;
    if ((thisop == '+') || (thisop == '-'))
    {
       dfdx = new char[dgdx_len+1+dhdx_len+1]; // Use malloc instead of new in C.
       std::strcpy (dfdx, dgdx);
       dfdx[dgdx_len] = thisop;                // There's no need for calling strcat here.
       std::strcpy (dfdx+dgdx_len+1, dhdx);    // Nor here.
    }
    ...
    delete[] dfdx; // Replace with free if you are using C, but never omit this.
    There are some issues with the above. What if thisop is '-' and dhdx is "a+b*x+c*x^2"? You probably want to put parentheses around the embedded dhdx. I'll leave that as an exercise for the OP. You may also want to simplify the resultant expression. That is not an exercise for the OP. It means you need a symbolic mathematics library or a symbolic mathematics tool.

    You might want to rethink your use of C/C++ here.
     
    Last edited: Jun 17, 2015
  10. Jun 17, 2015 #9

    Svein

    User Avatar
    Science Advisor

    If you still want to use C:

    Declare a local character array with space for the longest possible string plus some extra headroom: char temp[MAX_OP_SIZE];
    Then do what I said above (and introduce the parentheses suggested by D H):
    n = sprintf(temp, "(%s) %c (%s)", dgdx, thisop, dhdx);
    Then store the result:
    dfdx = strdup(temp);
    And you want to check for errors:
    if (dfdx==NULL)
    // Run in circles, scream and shout...
     
  11. Jun 18, 2015 #10
    Good call. I can't believe I didn't think of that.

    I'm handrolling a tool for symbolic differentiation and don't have any plan to simplify. Right now it looks atrocious (http://codepad.org/mRv44sr1), but is close to working. The insertInTree function is what's giving me trouble (I asked a question about it here: http://stackoverflow.com/questions/...algorithm-to-insert-a-node-in-a-function-tree).
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook