Thread: Reusing code blocks for different variables

  1. #1
    Registered User
    Join Date
    Sep 2006
    Posts
    35

    Reusing code blocks for different variables

    If I have a list of variables which all should be executed by the same code block, but don't want to involve an extra function, how would I go about doing so?

    For examples, I have three variables:
    char *c1, *c2, *c3;

    Now, I want to execute the same code on all the variables, such as (for simplicity's sake, I'm only showing the example for c1):
    Code:
    if ((c1 = malloc(sizeof(char))) == NULL) {
            return -1;
    }
    I would really like anything that can help compact my code. Of course, thanks in advance for any help.

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    How about:
    Code:
    char *c1 = malloc(sizeof(char));
    char *c2 = malloc(sizeof(char));
    char *c3 = malloc(sizeof(char));
    
    if( !(c1 && c2 && c3) )  return -1;
    I don't like making assumptions about what people need, but an array of pointers may be easier to deal with.

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    35
    Thanks for replying, citizen. Unfortunately, the code blocks that I'm actully using for my program are quite a bit longer than just a simple malloc. I initially thought char** would work, but I was hoping that there was something like an enum or a case switch which would serve my purpose better.

    Just for assistance purposes, the following code looks somewhat like the one I want to replicate:
    Code:
    do {
            if (*current_char != '&') {
                    if ((tmp = realloc(source, sizeof(char) * (strlen(source) + 2))) == NULL) {
                            return -1;
                    }
                    source = tmp;
                    strncat(source, (char*)current_char, sizeof(char));
            } else {
                    if ((tmp = realloc(source, sizeof(char) * (strlen(source) + size + 1))) == NULL) {
                            return -1;
                    }
                    source = tmp;
                    strncat(source, user, size * sizeof(char));
            }
    } while (*current_char++ != ' ' && *current_char != NULL);
    In the above, char* source would be interchanged with other char*'s. Does that clear matters up? Thanks again.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    First of all, it would have been better if you posted that in the beginning. My earlier answer is now completely useless.

    > I initially thought char** would work, but I was hoping that there was something like an enum or a case switch which would serve my purpose better
    Maybe they do. What is your purpose?

    As far as your code goes, there's not much you can do to make it shorter I think. This is because you do different things with the memory when the condition changes. You can make it easier to read.

    > if ((tmp = realloc(source, sizeof(char) * (strlen(source) + 2))) == NULL)
    Personally I don't like seeing things like this, when you can normally call memory allocators in one statement and then examine the pointer.

    > strncat(source, (char*)current_char, sizeof(char));
    This appends one character, and the cast doesn't look necessary from what you've posted.

    > strncat(source, user, size * sizeof(char));
    Multiplication is unnecessary, since size * sizeof(char) = size.
    Last edited by whiteflags; 09-11-2006 at 09:13 PM.

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    35
    Basically, I pass in a space delimited line, such as
    Code:
    user group element
    From there, I use *current_char++ to traverse the line, adding each word to a different existing char* based on its position. Therefore, the word "user" would be added to char* c1, "group" to char* c2, and element to char* source. Now, since the traversal code should be the same, I essentially just want to reuse that block, only substituting the target string. I hope I made myself clearer in that explanation.

    As for responses to your post:
    > strncat(source, (char*)current_char, sizeof(char));
    This appends one character, and the cast doesn't look necessary from what you've posted.
    Yes, it's definitely not necessary, but I added it to stop the compiler from warning me about it. Are there any downsides to doing that?
    > strncat(source, user, size * sizeof(char));
    Multiplication is unnecessary, since size * sizeof(char) = size.
    Currently, side = strlen(user), so wouldn't it be necessary to multiply that by the size of a char? I know that sizeof(char) == 1, but what if that's not the case in the future?

    I'm not trying to sound arrogant, since I'm really quite new to C. I just want to make sure what I'm doing is correct. Thanks again.

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    It sounds like you're parsing text to obtain words. There are much simpler ways to do it.
    http://www.daniweb.com/code/snippet318.html

    I also suggest that you look at the page for realloc. There are some things you should know about it before using it at random:
    http://www.daemon-systems.org/man/realloc.3.html

    > Are there any downsides to doing that?
    I wouldn't use strncat the way that you are, because strncat expects a \0 terminated string, and this is not what you provide. It's purpose is to squish strings together, not append single characters to strings. To do that you can access the string itself. Probably source[oldlen] = *current_char;

    > I know that sizeof(char) == 1, but what if that's not the case in the future?
    The char data type has always been one byte long since I started programming, and is very likely to stay that way. Rather than changing the size of char and breaking legacy code, wider characters have their own data types.
    Last edited by whiteflags; 09-12-2006 at 03:04 AM. Reason: grammar

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    35
    Quote Originally Posted by citizen
    It sounds like you're parsing text to obtain words. There are much simpler ways to do it.
    http://www.daniweb.com/code/snippet318.html
    I took a look at the strcspn function and now have 2 questions.

    1. How do I pass in all whitespace as the delimiter? Basically, instead of just specifying " ", I also want to account for " " (2 spaces) or "\t".
    2. In my current parsing algorithm, I don't even want to parse anything beyond the second word unless both the first and second words satisfy certain conditions. Therefore, if both fail the specified condition, I just skip the rest of the parse. How can I use strcspn to take that into account? Or if it can't, would I just use the "source[oldlen] = *current_char" method?
    3. As you might notice in my second post, I traversed character by character so that I could strncat *user to *source whenever *current_char == "&". If I were to switch to a strcspn method, how could I implement that functionality without retraversing the string again and replacing (with regex or some equivalent)?
    Last edited by Queue; 09-13-2006 at 11:52 PM.

  8. #8
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    If you want fined-tuned parsing, you should go make your own parser (maybe based on FSM). Then you can implement switches and special goodies to your heart's content.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  9. #9
    Registered User
    Join Date
    Sep 2006
    Posts
    35
    Quote Originally Posted by jafet
    If you want fined-tuned parsing, you should go make your own parser (maybe based on FSM). Then you can implement switches and special goodies to your heart's content.
    Could you please define FSM for me? Also, my current implementation (traversing each line character by character) serves as a parser, does it not?

  10. #10
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Could you please define FSM for me?
    google("c programming FSM")[0] = http://safari.oreilly.com/0131774298/ch08lev1sec6

    FSM = Finite State Machine
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  11. #11
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Quote Originally Posted by Queue
    I took a look at the strcspn function and now have 2 questions.

    1. How do I pass in all whitespace as the delimiter? Basically, instead of just specifying " ", I also want to account for " " (2 spaces) or "\t".
    2. In my current parsing algorithm, I don't even want to parse anything beyond the second word unless both the first and second words satisfy certain conditions. Therefore, if both fail the specified condition, I just skip the rest of the parse. How can I use strcspn to take that into account? Or if it can't, would I just use the "source[oldlen] = *current_char" method?
    3. As you might notice in my second post, I traversed character by character so that I could strncat *user to *source whenever *current_char == "&". If I were to switch to a strcspn method, how could I implement that functionality without retraversing the string again and replacing (with regex or some equivalent)?
    That code is suited to single-character delimiters, although more than one delimiter may be used (any one character).

    For multiple whitespace as a delimiter, I might do something with pointers and isspace. Start at the beginning; move the end to the whitespace and then the end minus the start is the length; (do something); move the start to the beginnig of the whitespace (the end), then eat the spaces and move the end; lather, rinse, repeat.
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    void parse(const char *text)
    {
       const char *end = text, *start = text;
       while ( *start != '\0'  )
       {
          while ( *end != '\0' && !isspace(*end) )
          {
             ++end;
          }
          /*
           * Do stuff.
           */
          printf("\"%.*s\"\n", end - start, start);
          /*
           * Move the start and end pointers.
           */
          start = end;
          while ( *start != '\0' && isspace(*start) )
          {
             ++start;
          }
          end = start;
       }
    }
    
    int main(void)
    {
       const char *line[] = { "text1  text2 \t text3", " text1\rtext2\n", "" };
       size_t j;
       for ( j = 0; j < sizeof line / sizeof *line; ++j )
       {
          puts("---");
          parse(line[j]);
       }
       return 0;
    }
    
    /* my output
    ---
    "text1"
    "text2"
    "text3"
    ---
    ""
    "text1"
    "text2"
    ---
    */
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  12. #12
    Registered User
    Join Date
    Sep 2006
    Posts
    35
    Thanks Dave_Sinkula, the while(isspace()) condition should satisfy my whitespace delimiter.

    While reading over FSM-related articles, I have had trouble differentiating between FSM's and "regular" logic. Just how exactly does one store the different states (code-wise, I mean)?

    On the other hand, I'm not even quite sure how to even go about implementing the FSM in my particular case. Can someone provide the barebones pseudocode as to how that would work? An example line from the file I want to parse might look like:
    Code:
    user1,user2 group1,group2,group3 string1 string2 string3
    As one can see, the line is separated into 5 whitespace delimited elements. In the first element, each comma delimited sub-element will be passed to another function. The result of that function should dictate the following step. For example, if the function returns 0, the second element should be skipped. However, if the function returns 1, it shouldn't. The same rules generally apply to the second element, though the corresponding function will be different. If that function returns 0, proceed with parsing. If it returns 1, exit. After the first two elements, I then want the FSM to assign string1, string2, and string3 to char* string1, char* string2, and char* string3, respectively.

    I'd appreciate any help I can get, and I'm really only hoping for pseudocode (and any advice, of course). Thanks in advance.

  13. #13
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Hm. I dunno about a full-fledged FSM for this, I've never written a complex parser. Some ideas...
    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h>
    
    int myfunction(const char *text, int len)
    {
       const char *comma = strchr(text, ',');
       if ( comma == NULL )
       {
          return 0;
       }
       printf("\"%.*s\"\n", len, text);
       fflush(stdout);
       return 1;
    }
    
    void parse(const char *text, int (*foo)(const char *, int len))
    {
       const char *end = text, *start = text;
       while ( *start != '\0' )
       {
          while ( *end != '\0' && !isspace(*end) )
          {
             ++end;
          }
          /*
           * Do stuff.
           */
          if ( !foo(start, end -  start) )
          {
             break;
          }
          /*
           * Move the start and end pointers.
           */
          start = end;
          while ( *start != '\0' && isspace(*start) )
          {
             ++start;
          }
          end = start;
       }
    }
    
    int main(void)
    {
       const char line[] = "user1,user2 group1,group2,group3 string1 string2 string3";
       parse(line, myfunction);
       return 0;
    }
    
    /* my output
    "user1,user2"
    "group1,group2,group3"
    */
    Some example of checking for a comma.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  14. #14
    Registered User
    Join Date
    May 2006
    Posts
    17
    I don't know if you actually want to write this or if you just want a parser, but in the latter case you could consider looking at Flex and Bison. They are parser generators and are fairly easy to use.

  15. #15
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    But I don't think this fella is writing a whole new language; (s)he doesn't need a compiler-quality parser. Learning Flex/Bison/Yacc may take as much time as, if not more than, to just write a decent-quality string parser from scratch.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. keeping track of code blocks
    By Aisthesis in forum C++ Programming
    Replies: 9
    Last Post: 05-12-2009, 10:13 PM
  2. Replies: 23
    Last Post: 04-20-2009, 07:35 AM
  3. Dev and Code Blocks
    By swgh in forum Game Programming
    Replies: 3
    Last Post: 04-07-2006, 07:21 PM
  4. Replies: 4
    Last Post: 01-16-2002, 12:04 AM
  5. Replies: 2
    Last Post: 09-10-2001, 12:00 PM