Thread: Why is this statement being skipped?

  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    23

    Why is this statement being skipped?

    Look at this piece of code:
    Code:
    1071                    {
    1072                            b = strchr(a, '\0');
    1073                            finished = 1;
    1074                    }
    1075
    1076                    strncpy(temp, a, (b-a));
    1077                    strcat(temp, ""); /* add a null at the end */
    1078
    1079                    a = b + 1;
    1080
    When I was debugging the program I noticed that lie 1077 was being skipped for no reason at all.

    Check out the GDB output:

    1076 strncpy(temp, a, (b-a));
    4: b = 0x5042b5 "/../test"
    3: a = 0x5042b1 "test/../test"
    2: simple_path = 0x5042b0 "/test/../test"
    1: temp = '\0' <repeats 79 times>
    (gdb) next
    1079 a = b + 1;
    4: b = 0x5042b5 "/../test"
    3: a = 0x5042b1 "test/../test"
    2: simple_path = 0x5042b0 "/test/../test"
    1: temp = "test", '\0' <repeats 75 times>
    Yes I did have the correct version of the program compiled...


    On a side note:
    when I'm dynamically allocating space for a string, which one of these pieces of code is correct?
    Code:
    new_string = malloc(strlen(old_string) + 1);
    or
    Code:
    new_string = malloc( (strlen(old_string) + 1) * sizeof(char));
    Last edited by TalonStriker; 11-10-2007 at 07:14 AM.

  2. #2
    Registered User
    Join Date
    Nov 2007
    Posts
    23
    I'm confused, I changed 1077 to
    Code:
    *(temp + (b-a+1) * sizeof(char)) = '\0'; /* add a NUL at the end */
    and its still being skipped

  3. #3
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by TalonStriker View Post
    On a side note:
    when I'm dynamically allocating space for a string, which one of these pieces of code is correct?
    Code:
    new_string = malloc(strlen(old_string) + 1);
    or
    Code:
    new_string = malloc( (strlen(old_string) + 1) * sizeof(char));
    sizeof(char) is 1 by definition. So I'd go for the first version

    Code:
    strcat(temp, ""); /* add a null at the end */
    The comment is wrong.
    The statement means "append nothing to tmp".
    You have a smart compiler that eleminates "doing nothing".
    Kurt

  4. #4
    Devil™
    Join Date
    Oct 2007
    Location
    IIT-Kharagpur, India
    Posts
    104
    Quote Originally Posted by TalonStriker View Post
    Code:
    new_string = malloc(strlen(old_string) + 1);
    or
    Code:
    new_string = malloc( (strlen(old_string) + 1) * sizeof(char));
    it is better to go for the 2nd one as the size of a data type is not guranteed to be same on every system that you compile or use it
    C's Motto: who cares what it means? I just compile it!!

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You do realize that the code
    Code:
    strcat(x, "");
    doesn't actually DO ANYTHING, don't you? The reason is that strcat() searches for the end of the string (NUL character), then appends the string. But since the string is empty, all it would actually do is replace the NUL that it found with the new NUL that came from the empty string. Since all NUL's are equal, there is no point in replacing one with another - it won't change anything.

    If you want to guarantee that there is a NUL on the end of your string, you CAN NOT use strcat to achieve that, because strcat itself relies on the NUL being there. You could do
    Code:
    temp[b-a] = 0;
    By the way, if you want to find the end of the string, using strchr() is most likely less efficient than:
    Code:
    b = &a[strlen(a)];
    THis is because strlen() is one of the more frequent string operations, and it's much more likely to be highly optimized than any other string operation. strcpy and strcat are obviously also very frequent and highly optimized, but neither really does what you want here.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    835
    > it is better to go for the 2nd one as the size of a data type is not guranteed to be same on every system that
    > you compile or use it

    sizeof(char) is guaranteed to be 1 byte by the Standard, so portability is not an issue (the number of bits IN a byte, on the other hand, is implementation-defined, but malloc() doesn't need to know about that).

  7. #7
    Devil™
    Join Date
    Oct 2007
    Location
    IIT-Kharagpur, India
    Posts
    104
    Quote Originally Posted by robatino View Post
    > it is better to go for the 2nd one as the size of a data type is not guranteed to be same on every system that
    > you compile or use it

    sizeof(char) is guaranteed to be 1 byte by the Standard, so portability is not an issue (the number of bits IN a byte, on the other hand, is implementation-defined, but malloc() doesn't need to know about that).
    I dont know if its standard to be 1 byte on all systems or not..
    as I am not sure.. I always use sizeof() for all that stuff..
    I am sure this cant be wrong
    C's Motto: who cares what it means? I just compile it!!

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by gibsosmat View Post
    I dont know if its standard to be 1 byte on all systems or not..
    as I am not sure.. I always use sizeof() for all that stuff..
    I am sure this cant be wrong
    Indeed it's never WRONG to use sizeof(char) - but it's GUARANTEED by the C standard that a char is of size 1 - whatever size 1 means is up to the implementation - technically, it could be 16 bits, 9 bits, 7 bits or any other number of bits. Commonly it is 8 bits. But the only thing that is guaranteed is that "sizeof(char) == 1".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Devil™
    Join Date
    Oct 2007
    Location
    IIT-Kharagpur, India
    Posts
    104
    hmm..
    ok.. I will use it to be one..
    C's Motto: who cares what it means? I just compile it!!

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    835
    > technically, it could be 16 bits, 9 bits, 7 bits or any other number of bits.

    It has to be >= 8 bits, based on the guaranteed ranges for signed char (at least -127 to +127) and/or unsigned char (0 to at least 255).

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    http://c-faq.com/malloc/sizeofchar.html

    Writing
    p = malloc ( numRequired * sizeof *p );
    always works, and saves you having to remember what to do. Plus, if the type of p changes, it will continue to do the right thing!

    The problem with thinking "oh, it's a char, therefore I can leave the sizeof off" is that sooner or later, you'll make the wrong choice and then start to ponder the nature of the random crashing.

    Writing good code is in part adopting styles and habits which are less error prone than other approaches (like always using braces even when they might be considered optional).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  12. #12
    Registered User
    Join Date
    Nov 2007
    Posts
    23
    I think I'll continue using the size of version, it makes more sense to me that way... I just wanted to make sure that the first version wasn't wrong

    Quote Originally Posted by ZuK View Post
    sizeof(char) is 1 by definition. So I'd go for the first version

    Code:
    strcat(temp, ""); /* add a null at the end */
    The comment is wrong.
    The statement means "append nothing to tmp".
    You have a smart compiler that eleminates "doing nothing".
    Kurt
    oh yeah...thanks for pointing that out.

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    835
    The point the link makes about introducing a size_t is interesting (I have some code where I explicitly cast one of the terms to size_t to make sure the argument is calculated correctly, so I should have thought of it). But doesn't this mean that the sizeof() should always be the first term in the expression, to make sure the whole thing gets evaluated as a size_t, instead of the last, which is conventional? For example, if n1 and n2 are type int, then
    Code:
    p = malloc(n1 * n2 * sizeof *p);
    would first evaluate n1 * n2 as int, since multiplication associates left to right, and possibly overflow. Putting the "sizeof *p" first makes the whole thing evaluate as size_t.

    Edit: Of course, with size_t, overflow is still possible, but at least it won't happen unless the value won't fit in a size_t, in which case the allocation would be impossible anyway.
    Last edited by robatino; 11-10-2007 at 11:31 AM.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    I was going to agree with you, then I tried this and got the right answer with gcc and VC6.

    On the face of it, a*b should overflow.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    int main (int argc, char** argv)
    {
        short int a = 0x4000;
        short int b = 0x0010;
        size_t    c = a * b * sizeof a;
        printf("&#37;lx\n", (unsigned long)c );
        return 0;
    }
    
    $ gcc foo.c
    $ ./a.exe
    80000
    I don't know whether this is just implementation luck, or whether there is some rule which states that a sequence of identical operations are automatically cast to the largest type to begin with.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    Registered User
    Join Date
    Sep 2006
    Posts
    835
    If I set a short int ctmp to a * b, then set c equal to ctmp * sizeof a, it fails as expected. On the other hand, if I put a * b in parentheses inside the original code, it still succeeds. Strange.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Usefulness of the "else if" statement
    By gn17 in forum C Programming
    Replies: 7
    Last Post: 08-12-2007, 05:19 AM
  2. If Else statement problem
    By doofusboy in forum C Programming
    Replies: 2
    Last Post: 11-09-2005, 07:18 AM
  3. if/break statement
    By Apropos in forum C++ Programming
    Replies: 7
    Last Post: 02-22-2005, 02:33 PM
  4. string & if statement
    By Curacao in forum C++ Programming
    Replies: 4
    Last Post: 05-02-2003, 09:56 PM
  5. Uh-oh! I am having a major switch problem!
    By goodn in forum C Programming
    Replies: 4
    Last Post: 11-01-2001, 04:49 PM