sizeof array via pointer

M

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???)
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
 
A

Alf P. Steinbach

* 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
 
F

Fred Zwarts

Mark S. said:
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
 
M

Mark S.

Alf said:
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!
 
V

Vladimir Jovic

Alf said:
* Mark S.:
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 :)
 
H

hanukas

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);
 
A

Alf P. Steinbach

* 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 :) )
 
A

Alf P. Steinbach

* 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 :) )
 
A

Alf P. Steinbach

* 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 :) )
 
M

Mark S.

blargg said:
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
 
M

Mark S.

Alf said:
* Mark S.:
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...
 
A

Alf P. Steinbach

* 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
 
V

Vladimir Jovic

Alf said:
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?
 
M

Mark S.

Alf said:
* 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!
 
M

Mark S.

Vladimir said:
Alf said:
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.
 
A

Alf P. Steinbach

* Mark S.:
Alf said:
* 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
 
M

Mark S.

Alf said:
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).
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;)?
 
A

Alf P. Steinbach

* Mark S.:
Alf said:
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.

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
 
A

Alf P. Steinbach

* 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.

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/>.
 
J

James Kanze

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:

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.)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top