sizeof array via pointer

Discussion in 'C++' started by Mark S., Apr 8, 2009.

  1. Mark S.

    Mark S. Guest

    Hi,
    I want to access an array via a pointer and get the size of the array,
    but sadly I don't know the correct syntax for it:

    int main()
    {
    char c[10];
    char* cp = c;
    cp[3] = 'b'; // works
    int a = sizeof(cp); // this doesn't (returns 4 - why???)
    a = sizeof(*cp); // neither does this (returns 1)
    }

    So how do I get the correct size of c via the pointer (of course, the
    goal is to use this within a function)???

    Thank you in advance!
    Mark
    Mark S., Apr 8, 2009
    #1
    1. Advertising

  2. * Mark S.:
    > Hi,
    > I want to access an array via a pointer and get the size of the array,
    > but sadly I don't know the correct syntax for it:
    >
    > int main()
    > {
    > char c[10];
    > char* cp = c;
    > cp[3] = 'b'; // works
    > int a = sizeof(cp); // this doesn't (returns 4 - why???)


    It giveth the size of the pointer.


    > a = sizeof(*cp); // neither does this (returns 1)


    It giveth the size of the pointer's referent, a 'char'.


    > }
    >
    > So how do I get the correct size of c via the pointer (of course, the
    > goal is to use this within a function)???


    You can't get the array size via the pointer.

    The information simply isn't there, at least as far as standard C++ is concerned.

    Instead of raw arrays, use a std::vector or a std::string.

    #include <vector>
    #include <iostream>

    int main()
    {
    using namespace std;
    vector<char> c( 10 );

    c.at( 3 ) = 'b';
    cout << v.size() << endl;
    }

    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 8, 2009
    #2
    1. Advertising

  3. Mark S.

    Fred Zwarts Guest

    "Mark S." <> wrote in message news:49dc46e6$-ulm.de...
    > Hi,
    > I want to access an array via a pointer and get the size of the array,
    > but sadly I don't know the correct syntax for it:
    >
    > int main()
    > {
    > char c[10];
    > char* cp = c;


    As you declared cp as char*, it a pointer to a char.
    It is not a pointer to an array of chars.

    > cp[3] = 'b'; // works
    > int a = sizeof(cp); // this doesn't (returns 4 - why???)
    > a = sizeof(*cp); // neither does this (returns 1)
    > }
    >
    > So how do I get the correct size of c via the pointer (of course, the
    > goal is to use this within a function)???
    >
    > Thank you in advance!
    > Mark
    Fred Zwarts, Apr 8, 2009
    #3
  4. Mark S.

    Mark S. Guest

    Alf P. Steinbach wrote:
    >> So how do I get the correct size of c via the pointer (of course, the
    >> goal is to use this within a function)???

    >
    > You can't get the array size via the pointer.
    >
    > The information simply isn't there, at least as far as standard C++ is
    > concerned.


    That is strange because then I don't understand how this exercise is
    meant (Thinking in C++, chapter 4, exercise 18):
    http://www.linuxtopia.org/online_books/programming_books/thinking_in_c /Chapter04_019.html

    Write a function that takes a char* argument. Using new, dynamically
    allocate an array of char that is the size of the char array that’s
    passed to the function. Using array indexing, copy the characters from
    the argument to the dynamically allocated array (don’t forget the null
    terminator) and return the pointer to the copy. In your main( ), test
    the function by passing a static quoted character array, then take the
    result of that and pass it back into the function. Print both strings
    and both pointers so you can see they are different storage. Using
    delete, clean up all the dynamic storage.

    How can I determine the size of the array if all I get is the pointer to
    the array?

    Thank you for your time!
    Mark S., Apr 8, 2009
    #4
  5. Alf P. Steinbach wrote:
    > * Mark S.:
    >> Alf P. Steinbach wrote:
    >>>> So how do I get the correct size of c via the pointer (of course,
    >>>> the goal is to use this within a function)???
    >>>
    >>> You can't get the array size via the pointer.
    >>>
    >>> The information simply isn't there, at least as far as standard C++
    >>> is concerned.

    >>
    >> That is strange because then I don't understand how this exercise is
    >> meant (Thinking in C++, chapter 4, exercise 18):
    >> http://www.linuxtopia.org/online_books/programming_books/thinking_in_c /Chapter04_019.html
    >>
    >>
    >> Write a function that takes a char* argument. Using new, dynamically
    >> allocate an array of char that is the size of the char array that’s
    >> passed to the function. Using array indexing, copy the characters from
    >> the argument to the dynamically allocated array (don’t forget the null
    >> terminator) and return the pointer to the copy. In your main( ), test
    >> the function by passing a static quoted character array, then take the
    >> result of that and pass it back into the function. Print both strings
    >> and both pointers so you can see they are different storage. Using
    >> delete, clean up all the dynamic storage.

    >
    > Hm, hm, best advice is to contact Bruce (the correct one![1]), enclosing
    > a copy of this response, so that he can fix the exercise text.
    >
    >
    >> How can I determine the size of the array if all I get is the pointer
    >> to the array?

    >
    > You can't determine the size of the array itself.
    >
    > That's just an unfortunate wording in the exercise, not to be taken
    > literally.
    >


    In the example, this should work:
    a = sizeof(c);
    no?

    Not arguing that it is possible to do what is requested in the exercise
    text :)
    Vladimir Jovic, Apr 8, 2009
    #5
  6. Mark S.

    hanukas Guest

    On Apr 8, 9:40 am, "Mark S." <> wrote:
    > Hi,
    > I want to access an array via a pointer and get the size of the array,
    > but sadly I don't know the correct syntax for it:
    >
    > int main()
    > {
    >         char c[10];
    >         char* cp = c;
    >         cp[3] = 'b';  // works
    >         int a = sizeof(cp);     // this doesn't (returns 4 - why???)
    >         a = sizeof(*cp);        // neither does this (returns 1)
    >
    > }
    >
    > So how do I get the correct size of c via the pointer (of course, the
    > goal is to use this within a function)???


    void myfunc(char* data, int size);

    myfunc(c, 10);
    hanukas, Apr 8, 2009
    #6
  7. * Vladimir Jovic:
    >
    > In the example, this should work:
    > a = sizeof(c);
    > no?


    For an array of char 'c', yes, because sizeof(char) is 1 by definition.

    Otherwise you have to divide by the size of an array element, or alternatively
    use a function template to obtain the size.

    Dividing by the size of an element goes like this (idiomatic):

    size_t const size = sizeof(a)/sizeof(*a);

    It's usually encapsulated in a macro.

    The problem with this solution packaged in a macro is that it is *not type
    safe*, e.g., someone might use the macro with a pointer argument. One workaround
    could be to compile time assert that the argument is not a pointer. But as of
    C++98 that loses its advantage of being usable for locally defined types.

    The basic function template goes like this:

    template< typename T, size_t N >
    size_t size( T const (&)[N] ) { return N; }

    where the trick is that the array is passed by reference, so that it's not
    decayed to pointer, so that the size information is still available.

    The main advantage is that it's type safe, and the main problem is that it can't
    be used for array of local type.

    Another problem is that it doesn't deliver a compile time constant. When that's
    needed it's reformulated as a function returning a result of a type of byte size
    equal to the array's number of element. Then the client code has to apply sizeof
    to the result, and to avoid doing that directly it's in turn wrapped in a macro.


    Cheers & hth.,

    - Alf (master of C++98 array size determination :) )

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 8, 2009
    #7
  8. * Vladimir Jovic:
    >
    > In the example, this should work:
    > a = sizeof(c);
    > no?


    For an array of char 'c', yes, because sizeof(char) is 1 by definition.

    Otherwise you have to divide by the size of an array element, or alternatively
    use a function template to obtain the size.

    Dividing by the size of an element goes like this (idiomatic):

    size_t const size = sizeof(a)/sizeof(*a);

    It's usually encapsulated in a macro.

    The problem with this solution packaged in a macro is that it is *not type
    safe*, e.g., someone might use the macro with a pointer argument. One workaround
    could be to compile time assert that the argument is not a pointer. But as of
    C++98 that loses its advantage of being usable for locally defined types.

    The basic function template goes like this:

    template< typename T, size_t N >
    size_t size( T const (&)[N] ) { return N; }

    where the trick is that the array is passed by reference, so that it's not
    decayed to pointer, so that the size information is still available.

    The main advantage is that it's type safe, and the main problem is that it can't
    be used for array of local type.

    Another problem is that it doesn't deliver a compile time constant. When that's
    needed it's reformulated as a function returning a result of a type of byte size
    equal to the array's number of element. Then the client code has to apply sizeof
    to the result, and to avoid doing that directly it's in turn wrapped in a macro.


    Cheers & hth.,

    - Alf (master of C++98 array size determination :) )

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 8, 2009
    #8
  9. * Vladimir Jovic:
    >
    > In the example, this should work:
    > a = sizeof(c);
    > no?


    For an array of char 'c', yes, because sizeof(char) is 1 by definition.

    Otherwise you have to divide by the size of an array element, or alternatively
    use a function template to obtain the size.

    Dividing by the size of an element goes like this (idiomatic):

    size_t const size = sizeof(a)/sizeof(*a);

    It's usually encapsulated in a macro.

    The problem with this solution packaged in a macro is that it is *not type
    safe*, e.g., someone might use the macro with a pointer argument. One workaround
    could be to compile time assert that the argument is not a pointer. But as of
    C++98 that loses its advantage of being usable for locally defined types.

    The basic function template goes like this:

    template< typename T, size_t N >
    size_t size( T const (&)[N] ) { return N; }

    where the trick is that the array is passed by reference, so that it's not
    decayed to pointer, so that the size information is still available.

    The main advantage is that it's type safe, and the main problem is that it can't
    be used for array of local type.

    Another problem is that it doesn't deliver a compile time constant. When that's
    needed it's reformulated as a function returning a result of a type of byte size
    equal to the array's number of element. Then the client code has to apply sizeof
    to the result, and to avoid doing that directly it's in turn wrapped in a macro.


    Cheers & hth.,

    - Alf (master of C++98 array size determination :) )

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 8, 2009
    #9
  10. Mark S.

    Mark S. Guest

    blargg wrote:
    > Mark S. wrote:
    >> Alf P. Steinbach wrote:
    >>>> So how do I get the correct size of c via the pointer (of course, the
    >>>> goal is to use this within a function)???
    >>> You can't get the array size via the pointer.
    >>>
    >>> The information simply isn't there, at least as far as standard C++ is
    >>> concerned.

    >> That is strange because then I don't understand how this exercise is
    >> meant (Thinking in C++, chapter 4, exercise 18):
    >>

    > http://www.linuxtopia.org/online_books/programming_books/thinking_in_c /Chapter04_019.html
    >> Write a function that takes a char* argument. Using new, dynamically
    >> allocate an array of char that is the size of the char array that’s
    >> passed to the function. Using array indexing, copy the characters from
    >> the argument to the dynamically allocated array (don’t forget the null
    >> terminator) and return the pointer to the copy. In your main( ), test
    >> the function by passing a static quoted character array, then take the
    >> result of that and pass it back into the function. Print both strings
    >> and both pointers so you can see they are different storage. Using
    >> delete, clean up all the dynamic storage.
    >>
    >> How can I determine the size of the array if all I get is the pointer to
    >> the array?

    >
    > Sounds like it means the LENGTH of the C-style string you are given a
    > pointer to. In that case, juse use strlen(str) (and remember that the
    > length does NOT include the terminating zero).

    Oh, I thought he was just talking about a normal array. So my basic code
    was:
    char c[10];
    char* cp = c;
    int a = sizeof(c);

    And I thought I would go from there. I am also not sure yet what the
    sentence "In your main( ), test the function by passing a static quoted
    character array, then take the result of that and pass it back into the
    function." means. Does that mean that my function, which is supposed to
    take the char*, is supposed to be called like this:

    char* cp = f('abcd'); ???


    > But it also sounds like you
    > could choose a better book to learn C++ from. The author, who should be
    > experienced with C++, shouldn't be writing exercises which even a learner
    > can find ambiguity/error with.


    Well, I chose "Thinking in C++" because it was recommended on many sites
    throughout the net and it was well-written from my perspective. However,
    the exercises are not really contrived perfectly. The author indirectly
    admitted so himself (can't find the link though) when he stated that he
    just wrote down the exercises without actually giving them much thought
    them beforehand. For years he thought he could add a book with solutions
    but eventually gave up as it was too time-consuming (darn, I really wish
    I still had the link). Now, there is "The Annotated C++ Solutions
    Guide", but it is not written by him and only contains portions of the
    exercises (most of the early ones but the later the chapter, the fewer
    solved exercises: http://mindview.net/Books/TICPP/Solutions/SolnList).

    If you have a suggestion for a better comprehensible (!) book or
    tutorial (my first book was Stroustrup's "The C++ Programming Language
    which didn't help me at all), please post it as I'm always open to
    improve my learning effectiveness. ;)

    Kind regards
    Mark
    Mark S., Apr 9, 2009
    #10
  11. Mark S.

    Mark S. Guest

    Alf P. Steinbach wrote:
    > * Mark S.:
    >> Alf P. Steinbach wrote:
    >>>> So how do I get the correct size of c via the pointer (of course,
    >>>> the goal is to use this within a function)???
    >>>
    >>> You can't get the array size via the pointer.
    >>>
    >>> The information simply isn't there, at least as far as standard C++
    >>> is concerned.

    >>
    >> That is strange because then I don't understand how this exercise is
    >> meant (Thinking in C++, chapter 4, exercise 18):
    >> http://www.linuxtopia.org/online_books/programming_books/thinking_in_c /Chapter04_019.html
    >>
    >>
    >> Write a function that takes a char* argument. Using new, dynamically
    >> allocate an array of char that is the size of the char array that’s
    >> passed to the function. Using array indexing, copy the characters from
    >> the argument to the dynamically allocated array (don’t forget the null
    >> terminator) and return the pointer to the copy. In your main( ), test
    >> the function by passing a static quoted character array, then take the
    >> result of that and pass it back into the function. Print both strings
    >> and both pointers so you can see they are different storage. Using
    >> delete, clean up all the dynamic storage.

    >
    > Hm, hm, best advice is to contact Bruce (the correct one![1]), enclosing
    > a copy of this response, so that he can fix the exercise text.
    >
    >
    >> How can I determine the size of the array if all I get is the pointer
    >> to the array?

    >
    > You can't determine the size of the array itself.
    >
    > That's just an unfortunate wording in the exercise, not to be taken
    > literally.
    >
    > What you can do is to determine the number of valid data elements (e.g.
    > char's) in the array, based on some /convention/ for representing that
    > within the array. The main convention in C and C++ for character strings
    > is that the last valid element is zero. That is, not the value '0',
    > which in practice is 48, but the value char(0), which you can also write
    > as a literal as '\0'.


    Here is my solution:

    #include <iostream>
    using namespace std;

    #define PR(EX) cout << #EX << ": " << EX << endl;

    char* f(char* c)
    {
    int i = 0, size = 0;
    while ((int)c != 0)
    {
    size++;
    i++;
    }
    if (size > 0) { size++; }
    char* ca = new char[size];
    for (int j = 0; j < size; j++)
    {
    ca[j] = c[j];
    }
    return ca;
    }

    int main()
    {
    char cp[] = "abcd";
    PR(cp);
    PR(&cp);
    char* cf = f(cp);
    PR(cf);
    PR(&cf);
    delete ca; // Doesn't work
    }

    What do you think? The only question remains is how I delete ca at the
    end...
    Mark S., Apr 9, 2009
    #11
  12. * Mark S.:
    >

    [Doing a Bruce exercise]:
    >
    > Here is my solution:
    >
    > #include <iostream>
    > using namespace std;
    >
    > #define PR(EX) cout << #EX << ": " << EX << endl;
    >
    > char* f(char* c)


    The formal argument should better be

    char const* c

    so that the routine guarantees to not modify the actual argument.


    > {
    > int i = 0, size = 0;
    > while ((int)c != 0)
    > {
    > size++;
    > i++;
    > }


    You don't need to cast to int. And in general, whenever you feel the urge to
    introduce a cast, unless it's imposed on you by someone else's code, find the
    whip you have dedicated to this purpose and give yourself 10 painful lashings.
    At least! :)


    > if (size > 0) { size++; }


    Uhm, this is a bit dangerous. You're introducing a special case. Special cases
    are generally dangerous.


    > char* ca = new char[size];
    > for (int j = 0; j < size; j++)
    > {
    > ca[j] = c[j];
    > }
    > return ca;


    Here the bomb created by the earlier 'if' arms itself. It may or will detonate
    whenever client code tries to access a zero length string. Because you have
    special-cased it so that there's no valid memory at index 0.

    > }
    >
    > int main()
    > {
    > char cp[] = "abcd";


    Again, constness, like

    char const cp[] = "abcd";


    > PR(cp);
    > PR(&cp);
    > char* cf = f(cp);
    > PR(cf);
    > PR(&cf);
    > delete ca; // Doesn't work


    You need to use

    delete[] ca;

    because you used new[] to allocate it.


    > }
    >
    > What do you think? The only question remains is how I delete ca at the
    > end...


    OK.

    See comments above.


    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 9, 2009
    #12
  13. Alf P. Steinbach wrote:
    >> int main()
    >> {
    >> char cp[] = "abcd";

    >
    > Again, constness, like
    >
    > char const cp[] = "abcd";
    >
    >
    >> PR(cp);
    >> PR(&cp);
    >> char* cf = f(cp);
    >> PR(cf);
    >> PR(&cf);
    >> delete ca; // Doesn't work

    >
    > You need to use
    >
    > delete[] ca;
    >
    > because you used new[] to allocate it.
    >


    ca was not declared in main()
    Maybe Mark wanted to delete cf?
    Vladimir Jovic, Apr 9, 2009
    #13
  14. Mark S.

    Mark S. Guest

    Alf P. Steinbach wrote:
    > * Mark S.:
    >>

    > [Doing a Bruce exercise]:
    >>
    >> Here is my solution:
    >>
    >> #include <iostream>
    >> using namespace std;
    >>
    >> #define PR(EX) cout << #EX << ": " << EX << endl;
    >>
    >> char* f(char* c)

    >
    > The formal argument should better be
    >
    > char const* c
    >
    > so that the routine guarantees to not modify the actual argument.

    Just to make sure - this is mainly a safety measure, is that correct?
    Also, is "char const* c" the same as "const char* c"? I have also seen
    examples where people attach the '*' to the variable name, like "char
    const *c". Are these all identical?

    >> {
    >> int i = 0, size = 0;
    >> while ((int)c != 0)
    >> {
    >> size++;
    >> i++;
    >> }

    >
    > You don't need to cast to int. And in general, whenever you feel the
    > urge to introduce a cast, unless it's imposed on you by someone else's
    > code, find the whip you have dedicated to this purpose and give yourself
    > 10 painful lashings. At least! :)

    Alright, will use my Indie whip and tell my girlfriend not to go easy on
    me. :p
    Although I must say that casting is used quite extensively in "Thinking
    in C++" and I had the impression this is a very common procedure.

    >> if (size > 0) { size++; }

    >
    > Uhm, this is a bit dangerous. You're introducing a special case. Special
    > cases are generally dangerous.
    >
    >
    >> char* ca = new char[size];
    >> for (int j = 0; j < size; j++)
    >> {
    >> ca[j] = c[j];
    >> }
    >> return ca;

    >
    > Here the bomb created by the earlier 'if' arms itself. It may or will
    > detonate whenever client code tries to access a zero length string.
    > Because you have special-cased it so that there's no valid memory at
    > index 0.

    How about:
    do
    {
    size++;
    i++;
    } while (c != 0);
    ?

    >> int main()
    >> {
    >> char cp[] = "abcd";

    >
    > Again, constness, like
    >
    > char const cp[] = "abcd";

    Why? Doesn't this prevent me from manipulation the chars later on? What
    is the advantage of using const in this case?

    >
    >
    >> PR(cp);
    >> PR(&cp);
    >> char* cf = f(cp);
    >> PR(cf);
    >> PR(&cf);
    >> delete ca; // Doesn't work

    >
    > You need to use
    >
    > delete[] ca;
    >
    > because you used new[] to allocate it.

    No, that still doesn't work (`ca' was not declared in this scope). I
    understand scoping for "normal" objects, but should dynamically created
    storage be different? There must be some way to delete ca from a
    different place (and I'm not even saying "because it says so in the
    exercise description"), otherwise how does one get rid of the mess
    created by function?

    Thank you guys so much for all your time!
    Mark S., Apr 9, 2009
    #14
  15. Mark S.

    Mark S. Guest

    Vladimir Jovic wrote:
    > Alf P. Steinbach wrote:
    >>> int main()
    >>> {
    >>> char cp[] = "abcd";

    >>
    >> Again, constness, like
    >>
    >> char const cp[] = "abcd";
    >>
    >>
    >>> PR(cp);
    >>> PR(&cp);
    >>> char* cf = f(cp);
    >>> PR(cf);
    >>> PR(&cf);
    >>> delete ca; // Doesn't work

    >>
    >> You need to use
    >>
    >> delete[] ca;
    >>
    >> because you used new[] to allocate it.
    >>

    >
    > ca was not declared in main()
    > Maybe Mark wanted to delete cf?

    No, I thought I better delete the dynamically created array from the
    function.
    Mark S., Apr 9, 2009
    #15
  16. * Mark S.:
    > Alf P. Steinbach wrote:
    >> * Mark S.:
    >>>

    >> [Doing a Bruce exercise]:
    >>>
    >>> Here is my solution:
    >>>
    >>> #include <iostream>
    >>> using namespace std;
    >>>
    >>> #define PR(EX) cout << #EX << ": " << EX << endl;
    >>>
    >>> char* f(char* c)

    >>
    >> The formal argument should better be
    >>
    >> char const* c
    >>
    >> so that the routine guarantees to not modify the actual argument.

    > Just to make sure - this is mainly a safety measure, is that correct?


    Just like all use of types, yes.

    Others have remarked else-thread that not having the 'const' is a requirement of
    the exercise.

    It's a bad exercise text then, both requiring you to adopt unsafe practice, and
    requiring you to do the impossible!


    > Also, is "char const* c" the same as "const char* c"?


    Yes.

    There's a difference when you move the 'const' even further to the right, though.

    And for that reason, while all the examples in the standard have the 'const' on
    the left, some programmers (including me) prefer to have it on the right, which
    is the most general notation -- 'const' on the left is a special case.


    > I have also seen
    > examples where people attach the '*' to the variable name, like "char
    > const *c". Are these all identical?


    Yes. This latter use of whitespace is C-inspired notation. In C programming
    culture variables are important and types less so, while in C++ types are more
    important (what C++ added to C, the ++, was a number of facilities for more
    strong typing, including of course classes).



    >>> {
    >>> int i = 0, size = 0;
    >>> while ((int)c != 0)
    >>> {
    >>> size++;
    >>> i++;
    >>> }

    >>
    >> You don't need to cast to int. And in general, whenever you feel the
    >> urge to introduce a cast, unless it's imposed on you by someone else's
    >> code, find the whip you have dedicated to this purpose and give
    >> yourself 10 painful lashings. At least! :)

    > Alright, will use my Indie whip and tell my girlfriend not to go easy on
    > me. :p
    > Although I must say that casting is used quite extensively in "Thinking
    > in C++" and I had the impression this is a very common procedure.


    If it's there then shame on Bruce (that Bruce).


    >>> if (size > 0) { size++; }

    >>
    >> Uhm, this is a bit dangerous. You're introducing a special case.
    >> Special cases are generally dangerous.
    >>
    >>
    >>> char* ca = new char[size];
    >>> for (int j = 0; j < size; j++)
    >>> {
    >>> ca[j] = c[j];
    >>> }
    >>> return ca;

    >>
    >> Here the bomb created by the earlier 'if' arms itself. It may or will
    >> detonate whenever client code tries to access a zero length string.
    >> Because you have special-cased it so that there's no valid memory at
    >> index 0.

    > How about:
    > do
    > {
    > size++;
    > i++;
    > } while (c != 0);
    > ?


    Even more dangerous, forgetting to copy terminating zero in all other cases than
    an empty string.


    >>> int main()
    >>> {
    >>> char cp[] = "abcd";

    >>
    >> Again, constness, like
    >>
    >> char const cp[] = "abcd";

    > Why? Doesn't this prevent me from manipulation the chars later on?


    Yes.


    > What is the advantage of using const in this case?


    In this particular case, with a very very small program and copying of the data
    to an array, it's just about establishing good habits (the 'const' allows the
    compiler to optimize away the copying but it doesn't matter here, and I don't
    think any compiler does it anyway).

    Consider someone who doesn't have the habit of using 'const' everywhere
    applicable, and writes

    char* cp = "abcd";

    For compatibility with old C this is permitted.

    It will compile.

    And attempts at modififying the contents of that string will also compile, but
    are Undefined Behavior (e.g., might cause a crash at run time).


    >>> PR(cp);
    >>> PR(&cp);
    >>> char* cf = f(cp);
    >>> PR(cf);
    >>> PR(&cf);
    >>> delete ca; // Doesn't work

    >>
    >> You need to use
    >>
    >> delete[] ca;
    >>
    >> because you used new[] to allocate it.

    > No, that still doesn't work (`ca' was not declared in this scope). I
    > understand scoping for "normal" objects, but should dynamically created
    > storage be different? There must be some way to delete ca from a
    > different place (and I'm not even saying "because it says so in the
    > exercise description"), otherwise how does one get rid of the mess
    > created by function?


    I just mindlessly copied on your typo, which didn't even register anywhere with
    my scanner circuits.

    The main wrongness is the 'delete' (that the compiler won't detect), not the
    typo which it detects very easily.

    So, it should be

    delete[] cf;


    > Thank you guys so much for all your time!


    You're welcome.


    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 9, 2009
    #16
  17. Mark S.

    Mark S. Guest

    Alf P. Steinbach wrote:
    >> How about:
    >> do
    >> {
    >> size++;
    >> i++;
    >> } while (c != 0);
    >> ?

    >
    > Even more dangerous, forgetting to copy terminating zero in all other
    > cases than an empty string.

    Why? If I have the string "abcd", the size is 5. So when we get to
    for (int j = 0; j < size; j++)
    {
    ca[j] = c[j];
    }
    we also have ca[4] = c[4], which does copy the terminating zero. At
    least, my resulting examples were correct. This is also where the (int)
    cast came in handy - PR((int)cf[4]) actually displays the 0 instead of
    nothing (which could mean anything).

    >> What is the advantage of using const in this case?

    >
    > In this particular case, with a very very small program and copying of
    > the data to an array, it's just about establishing good habits (the
    > 'const' allows the compiler to optimize away the copying but it doesn't
    > matter here, and I don't think any compiler does it anyway).
    >
    > Consider someone who doesn't have the habit of using 'const' everywhere
    > applicable, and writes
    >
    > char* cp = "abcd";
    >
    > For compatibility with old C this is permitted.
    >
    > It will compile.
    >
    > And attempts at modififying the contents of that string will also
    > compile, but are Undefined Behavior (e.g., might cause a crash at run
    > time).

    I'm sorry, I don't understand. Why would that be undefined behavior? I
    thought part of the whole exercise was to learn to work with (and
    manipulate) C-strings. Why would I not want to be able to replace "abcd"
    with "abXd"? Sorry if I'm being stupid.

    > I just mindlessly copied on your typo, which didn't even register
    > anywhere with my scanner circuits.
    >
    > The main wrongness is the 'delete' (that the compiler won't detect), not
    > the typo which it detects very easily.
    >
    > So, it should be
    >
    > delete[] cf;

    Yes, this was suggested by Vladimir as well. But does this really delete
    the char* created in f? How does one check that some storage has been
    successfully freed? Also, if delete[] cf deletes the object that cf
    points to, how does one delete the pointer? Only through another pointer
    (like: char** cpp = new char* cp;)?
    Mark S., Apr 9, 2009
    #17
  18. * Mark S.:
    > Alf P. Steinbach wrote:
    >>> How about:
    >>> do
    >>> {
    >>> size++;
    >>> i++;
    >>> } while (c != 0);
    >>> ?

    >>
    >> Even more dangerous, forgetting to copy terminating zero in all other
    >> cases than an empty string.

    > Why?


    Good question!

    I thought it was a copying loop, meant to replace the copying code you quoted
    right above it.

    But now, looking, nay, peering, at the two statements inside, there's no
    copying, and it's clearly meant to replace the even earlier quoted size computation.

    Just up from my siesta...

    Now if Victor or someone else mentions coffee I'll be, well, better let's not
    mention that at all!


    > If I have the string "abcd", the size is 5. So when we get to
    > for (int j = 0; j < size; j++)
    > {
    > ca[j] = c[j];
    > }
    > we also have ca[4] = c[4], which does copy the terminating zero. At
    > least, my resulting examples were correct.


    Right.


    > This is also where the (int)
    > cast came in handy - PR((int)cf[4]) actually displays the 0 instead of
    > nothing (which could mean anything).


    Well you didn't do that in the code presented so far, so it appears to be some
    after-the-fact rationalization. But instead of the evil cast consider just
    adding 0. For example. Only when your code is almost chemically free of casts
    can you have any confidence that it is correct. Cast are just very very evil.

    By the way, macros are also generally a low level feature to be avoided.

    But they're required for header guards, and they're sort of OK for internal
    tracing and such stuff. Which is what you do here. In fact I don't know any
    trace facility that isn't macro based, so, right tool for the job.


    >>> What is the advantage of using const in this case?

    >>
    >> In this particular case, with a very very small program and copying of
    >> the data to an array, it's just about establishing good habits (the
    >> 'const' allows the compiler to optimize away the copying but it
    >> doesn't matter here, and I don't think any compiler does it anyway).
    >>
    >> Consider someone who doesn't have the habit of using 'const'
    >> everywhere applicable, and writes
    >>
    >> char* cp = "abcd";
    >>
    >> For compatibility with old C this is permitted.
    >>
    >> It will compile.
    >>
    >> And attempts at modififying the contents of that string will also
    >> compile, but are Undefined Behavior (e.g., might cause a crash at run
    >> time).

    > I'm sorry, I don't understand. Why would that be undefined behavior?


    Because the string literal is read-only. The compiler might place it in
    read-only memory. And not only might but is likely to.


    > I
    > thought part of the whole exercise was to learn to work with (and
    > manipulate) C-strings. Why would I not want to be able to replace "abcd"
    > with "abXd"? Sorry if I'm being stupid.


    It's a good question.

    The positive point about this exercise is that in addition to providing some
    familiarity with pointers and indexing, it's about what has to be done at the
    lowest level in order to get you a modifyable copy of a zero-terminated string
    when all you have is a pointer to that string.

    But generally, in C++ you can do that much more easily using std::string. :)


    >> I just mindlessly copied on your typo, which didn't even register
    >> anywhere with my scanner circuits.
    >>
    >> The main wrongness is the 'delete' (that the compiler won't detect),
    >> not the typo which it detects very easily.
    >>
    >> So, it should be
    >>
    >> delete[] cf;

    > Yes, this was suggested by Vladimir as well. But does this really delete
    > the char* created in f?


    Yes.


    > How does one check that some storage has been
    > successfully freed?


    One doesn't.

    One ensures that it is freed, as appropriate.

    Mainly, in C++ the way to do that is to use smart pointers and standard library
    containers. Some programmers (e.g. James Kanze) also use garbage collection. But
    no matter how you do it, in good C++ code there is seldom any 'delete' to be
    seen anywhere (done via containers or smart pointers), and 'new', if at all
    present, is wrapped in some function.


    > Also, if delete[] cf deletes the object that cf
    > points to, how does one delete the pointer? Only through another pointer
    > (like: char** cpp = new char* cp;)?


    You don't need to and you can't delete the pointer itself.

    The pointer value is just a value, the pointer storage is automatic storage.

    It's just like using 'int', there's no real difference.


    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 9, 2009
    #18
  19. * blargg:
    > Alf P. Steinbach wrote:
    > [...]
    >>> This is also where the (int)
    >>> cast came in handy - PR((int)cf[4]) actually displays the 0 instead of
    >>> nothing (which could mean anything).

    >> Well you didn't do that in the code presented so far, so it appears to be
    >> some
    >> after-the-fact rationalization. But instead of the evil cast consider just
    >> adding 0. For example. Only when your code is almost chemically free of casts
    >> can you have any confidence that it is correct. Cast are just very very evil.

    >
    > Here's an even terser way to promote a value to int if it's smaller:
    >
    > +value


    It's ungood because one has to think twice about it.

    Source code is about communicating to people, not (so much) about communicating
    to the compiler.

    That's why a cast is bad even when it just does what an implicit conversion
    would do, and why a non-idiomatic way such as '+value' is bad when there is more
    easily grokked or established idiomatic way.


    >>> So, it should be
    >>>> delete[] cf;
    >>> Yes, this was suggested by Vladimir as well. But does this really

    > delete
    >>> the char* created in f?

    >> Yes.

    >
    > f creates a character ARRAY, not a char*; this deletes the character
    > array that the char* POINTS TO.


    That was discussed in the part of the posting that you snipped.

    I discussed it because the OP asked, in the part of the posting you snipped, so
    your comment, following quoting of me, is redundant as a comment to the OP.

    It just irks me when people pretend to fail to understand plain English, change
    contexts, snip relevant material, and so on, to create some misleading
    impression, which, considering the above, is what it seems you did here.


    > The char* still exists after the delete,
    > though its value becomes indeterminate. You can still assign a new value
    > to the char* afterwards, for example.


    Actually, formally that's a bit problematic. :) But in practice you can, yes.


    >>> How does one check that some storage has been
    >>> successfully freed?

    >> One doesn't.

    >
    > Determine whether you're using a compiler that implements the standard.
    > If so, and if the pointer was one previously obtained from new and it
    > hasn't already been deleted, and you've invoked no undefined behavior,
    > then you can trust that it's been deleted.


    I'm sorry but as far as I can see that's gobbledegook.

    Possibly you meant that "then you can trust that a suitable 'delete' will
    destroy the object and free the allocated memory".

    But it's not necessarily the case that the memory has been freed, at least not
    in the sense of being freed for general reuse, for the relevant deallocation
    function (operator delete) may have been overridden for this class, or replaced
    globally. In the words of Niels Bohr, "It depends on the dog". However, the
    default, and the usual case, is that the memory is freed for general reuse.


    > Oh and use a compiler with a
    > debugging library that catches double delete and other violations.


    That's a good idea.


    Cheers & hth.,

    - Alf

    PS: for an introduction to pointers in C++, see my old pointers tutorial at
    <url: http://alfps.izfree.com/tutorials/pointers/>.

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
    Alf P. Steinbach, Apr 9, 2009
    #19
  20. Mark S.

    James Kanze Guest

    On Apr 9, 9:38 pm, blargg <> wrote:
    > Alf P. Steinbach wrote:


    > [...]


    > > > This is also where the (int) cast came in handy -
    > > > PR((int)cf[4]) actually displays the 0 instead of nothing
    > > > (which could mean anything).


    > > Well you didn't do that in the code presented so far, so it
    > > appears to be some after-the-fact rationalization. But
    > > instead of the evil cast consider just adding 0. For
    > > example. Only when your code is almost chemically free of
    > > casts can you have any confidence that it is correct. Cast
    > > are just very very evil.


    > Here's an even terser way to promote a value to int if it's
    > smaller:


    > +value


    Yes, but... In most cases where it matters, you don't need to
    do anything. Just use the char as an int, and let the compiler
    take care of the conversion. In the cases where it matters
    (e.g. outputting the integral value, instead of the character),
    the conversion becomes a significant part of the semantics, and
    not something that you want to sweep under the rug so that the
    reader won't see it. In such cases, I generally use
    static_cast. (There's also the case where I'm conceptually
    creating a temporary object, and will use the function
    notation---for reasons of consistency: it is the only
    possibility if I have 0 or more than 1 argument.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 9, 2009
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Derek
    Replies:
    7
    Views:
    24,331
    Ron Natalie
    Oct 14, 2004
  2. Trevor

    sizeof(str) or sizeof(str) - 1 ?

    Trevor, Apr 3, 2004, in forum: C Programming
    Replies:
    9
    Views:
    629
    CBFalconer
    Apr 10, 2004
  3. Vinu
    Replies:
    13
    Views:
    1,415
    Lawrence Kirby
    May 12, 2005
  4. Alex Vinokur

    sizeof (size_t) and sizeof (pointer)

    Alex Vinokur, Nov 12, 2007, in forum: C++
    Replies:
    19
    Views:
    789
    Ben Rudiak-Gould
    Nov 30, 2007
  5. Replies:
    46
    Views:
    652
    Shao Miller
    Jan 14, 2013
Loading...

Share This Page