By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,264 Members | 1,746 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,264 IT Pros & Developers. It's quick & easy.

How to get array size from a pointer?

P: n/a
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.
Oct 8 '08 #1
Share this Question
Share on Google+
30 Replies


P: n/a

<gg******@gmail.comwrote in message
news:37**********************************@o40g2000 prn.googlegroups.com...
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
Any empty string is not necessarily NULL.

{ "ABC","","GHI",0}

Three non-NULL strings followed by a NULL.

(vippstar will say NULL is not the same as 0. Whatever; if all you have to
mark the end is 0, then use it and hope that on your system 0 will never be
a legal string pointer.)

--
bartc

Oct 8 '08 #2

P: n/a
On Oct 8, 4:11 pm, "ggngu...@gmail.com" <ggngu...@gmail.comwrote:
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
char *y[] is an array of char * pointers. When a constant integer
expression with the value 0 appears in integer context, it becomes a
null pointer constant.
It's the same if you had written 0 or NULL.
How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.
Like strlen(); Strlen iterates until it encounters a byte whose value
is 0; Your function would iterate until it encounters a pointer whose
value is NULL.
Oct 8 '08 #3

P: n/a
On Oct 8, 4:22 pm, "Bartc" <b...@freeuk.comwrote:
<ggngu...@gmail.comwrote in message

news:37**********************************@o40g2000 prn.googlegroups.com...
It's part of a test and I'm stumped. There is a function
void foo(char **x)
The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:
char *y[] = { /* bunch of stuff */ }
and calling
foo(y)
In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

Any empty string is not necessarily NULL.
An empty string is _never_ NULL.
{ "ABC","","GHI",0}

Three non-NULL strings followed by a NULL.
What is a non-NULL string? A string can't be NULL! That doesn't make
sense.
(vippstar will say NULL is not the same as 0. Whatever; if all you have to
mark the end is 0, then use it and hope that on your system 0 will never be
a legal string pointer.)
Bollocks. Don't put words in my mouth ever again.
0 can never be a "legal string pointer".
NULL is guaranteed to compare unequal to all addresses of objects.

Oct 8 '08 #4

P: n/a
"gg******@gmail.com" <gg******@gmail.comwrites:
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
A little terminology: I'd call it a sentinel and I'd call "" an empty
string (I see you do to). "Null string" is just too confusing a term
to use safely.

Your question: when you write a string literal ("a", "hello", even "")
as an initialiser for a char * object, the characters in the string
are put into to an array somewhere (you don't need to care where) and
a pointer to that array is used as the value of the object. The array
is null-terminated: a byte with value zero is placed at the end.
Thus:

char *empty = "";

makes empty point to an array somewhere. That array need only contain
one character: a zero byte (sometimes called a null character).

C also permits any pointer to be set to a special value to show that
the pointer does not point to an object. This is a null pointer and
it quite different to a pointer that points to an array that happens
to start with a null character. Thus:

char *nowhere = 0;

makes nowhere a null pointer. You can also use the macro NULL if you
have included (one of) the right headers -- stddef.h for example.

Give a char pointer p, you can tell if it is a null pointer by asking:

if (p == 0) /* or p == NULL if you prefer */

In fact, simply writing

if (!p)

is enough but to tell if p points to an empty string, you must ask

if (*p == 0) /* or *p == '\0' if you prefer */

The same test can also be written p[0] == 0, !p[0] or simply !*p.
How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.
In short, it can't, but it can tell the difference between a null
pointer and a non-null pointer that points at a null character.

--
Ben.
Oct 8 '08 #5

P: n/a
On 8 okt, 15:11, "ggngu...@gmail.com" <ggngu...@gmail.comwrote:
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string ("").
There is no such thing as a null string.
The string literal "" denotes an empty string, which is a string that
contains only the terminating '\0' character.
However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
First, the binary representation of a null pointer (what you get when
using 0 in a *pointer* context) is not required to be all-bits-zero
(although it often is).

The way you can detect if you are dealing with an empty string or a
null pointer is like this:
* Each string, including empty strings, has an address that is
distinct from NULL.
* When using strings, you are alweays passing around the addresses of
the strings.
>
How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.
If you iterate over x, then *x == NULL indicates the end of the array.
**x == '\0' indicates an empty string (if *x != NULL).

Bart v Ingen Schenau
Oct 8 '08 #6

P: n/a
Bartc wrote:
>
<gg******@gmail.comwrote in message
news:37**********************************@o40g2000 prn.googlegroups.com...
>It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
Any empty string is not necessarily NULL.
He wrote NUL, not NULL. NUL is the name for an ASCII character which is
written '\0' in C (when the character set is ASCII).

Referring to what you said, rather than what he was talking about:

NULL is necessarily not a an empty string. The only byte in an empty
string has a null character (NUL on ASCII systems). If NULL expands to
an expression with arithmetic type, it will certainly compare equal to
that null character; even if NULL has a pointer type, it will probably
compare equal to a null character on most systems - (void*)0 is required
to be a null pointer, but (void*)i is not required to produce the same
result, even if i==0 (though it usually does).

However, NULL will never compare equal to an empty string. An empty
string has a pointer type, and points at the array containing the null
character which terminates it. In any such comparison, NULL converts to
a null pointer of the same type, and a null pointer is prohibited from
comparing equal to any pointer to an actual object.
{ "ABC","","GHI",0}

Three non-NULL strings followed by a NULL.

(vippstar will say NULL is not the same as 0. ...
vippstar is correct. It could be (void*)0, or (8-8) or '\0', among many
other possibilities. They will all compare equal to 0, however.
... Whatever; if all you have
to mark the end is 0, then use it and hope that on your system 0 will
never be a legal string pointer.)
0 is a null pointer constant. When it appears in a pointer context, it
is treated as a null pointer. A null pointer can never compare equal to
a pointer to any actual object or pointer. It is legal for a system to
have a pointer whose bits are all 0 that is not a null pointer. However,
on such a system, such a pointer can NOT be produced by initializing a
pointer object with a null pointer constant.
Oct 8 '08 #7

P: n/a

<vi******@gmail.comwrote in message
news:31**********************************@r37g2000 prr.googlegroups.com...
On Oct 8, 4:22 pm, "Bartc" <b...@freeuk.comwrote:
><ggngu...@gmail.comwrote in message

news:37**********************************@o40g200 0prn.googlegroups.com...
It's part of a test and I'm stumped. There is a function
void foo(char **x)
The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:
char *y[] = { /* bunch of stuff */ }
and calling
foo(y)
In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

Any empty string is not necessarily NULL.

An empty string is _never_ NULL.
I missed where the OP mentioned the null string "", and assumed that NULL
was also being used to signify an empty string.

However NULL to represent an empty string can be a useful technique
(although not recognised by standard functions), hence my comment.
>
>{ "ABC","","GHI",0}

Three non-NULL strings followed by a NULL.

What is a non-NULL string? A string can't be NULL! That doesn't make
sense.
Isn't that what I said? A string that is not NULL.
>(vippstar will say NULL is not the same as 0. Whatever; if all you have
to
mark the end is 0, then use it and hope that on your system 0 will never
be
a legal string pointer.)

B?ll?cks.
So eloquent.

--
Bartc

Oct 8 '08 #8

P: n/a
Bartc wrote:
>
<vi******@gmail.comwrote in message
news:31**********************************@r37g2000 prr.googlegroups.com...
>On Oct 8, 4:22 pm, "Bartc" <b...@freeuk.comwrote:
....
>>Any empty string is not necessarily NULL.

An empty string is _never_ NULL.

I missed where the OP mentioned the null string "", and assumed that
NULL was also being used to signify an empty string.

However NULL to represent an empty string can be a useful technique
(although not recognised by standard functions), hence my comment.
No, NULL can be used to represent a missing string. An empty string is a
string containing one null character; NULL does not qualify.
>>{ "ABC","","GHI",0}

Three non-NULL strings followed by a NULL.

What is a non-NULL string? A string can't be NULL! That doesn't make
sense.

Isn't that what I said? A string that is not NULL.
But all strings are not NULL, so that's a pointless phrase. Just say
"Three strings followed by a null pointer".
Oct 8 '08 #9

P: n/a
gg******@gmail.com <gg******@gmail.comwrote:
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.
An empty string ("") is represented as a pointer to a NUL byte (i.e. a byte
that has the value 0)
(A string is a pointer to a character array that is terminated by a NUL byte)

A plain 0 interpreted as a pointer is a null pointer which is different.
If a particular entry compares equal to NULL then it is a null pointer
(which in your case would indicate the end of your array 'y' of char
pointers.) If it does not compare equal to NULL, but points to a byte having
the value 0, then it is an empty string. (The remaining possibilities are
that it points to a non-NULL string, or that it is an invalid pointer in
which case you did something wrong.)

--
<Insert your favourite quote here.>
Erik Trulsson
er******@student.uu.se
Oct 8 '08 #10

P: n/a
gg******@gmail.com said:
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.

Your English description of the array contents is confusing. I suggest you
show us the actual initialisation code - i.e. replace /* bunch of stuff */
with the actual bunch of actual stuff.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Oct 8 '08 #11

P: n/a
gg******@gmail.com <gg******@gmail.comwrote:
>
However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever).
No. An empty string is like an empty box; a null pointer is no box at
all.
--
Larry Jones

Rats. I can't tell my gum from my Silly Putty. -- Calvin
Oct 8 '08 #12

P: n/a
"Bartc" <bc@freeuk.comwrites:
<vi******@gmail.comwrote in message
news:31**********************************@r37g2000 prr.googlegroups.com...
>On Oct 8, 4:22 pm, "Bartc" <b...@freeuk.comwrote:
[...]
>>Any empty string is not necessarily NULL.

An empty string is _never_ NULL.

I missed where the OP mentioned the null string "", and assumed that
NULL was also being used to signify an empty string.

However NULL to represent an empty string can be a useful technique
(although not recognised by standard functions), hence my comment.
[...]

Sure, you can use a null pointer to represent an empty string. You
can also use the number 42, or the string "this is an empty string",
to represent an empty string. You can use anything you like to
represent anything you like, as long as you're consistent about it.

But a null pointer *is not* an empty string, and it doesn't point to
an empty string. And, in my opinion, using a null pointer to
represent an empty string is a bad idea; it's too easy to accidentally
pass it to a function that doesn't know about your convention, and it
loses you the ability to distinguish between an empty string and the
absence of a string.

Finally, strings are not pointers. A pointer can point to a string; a
pointer cannot be a string.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Oct 8 '08 #13

P: n/a
On Oct 9, 12:48 am, Keith Thompson <ks...@mib.orgwrote:
>
But a null pointer *is not* an empty string, and it doesn't point to
an empty string. And, in my opinion, using a null pointer to
represent an empty string is a bad idea; it's too easy to accidentally
pass it to a function that doesn't know about your convention, and it
loses you the ability to distinguish between an empty string and the
absence of a string.

Finally, strings are not pointers. A pointer can point to a string; a
pointer cannot be a string.
Yes. In my opinion, the null/empty string is this string: ""; the null
pointer is this value: NULL.
Oct 8 '08 #14

P: n/a
"lo***************@gmail.c0m" <lo***************@gmail.comwrites:
On Oct 9, 12:48 am, Keith Thompson <ks...@mib.orgwrote:
>But a null pointer *is not* an empty string, and it doesn't point to
an empty string. And, in my opinion, using a null pointer to
represent an empty string is a bad idea; it's too easy to accidentally
pass it to a function that doesn't know about your convention, and it
loses you the ability to distinguish between an empty string and the
absence of a string.

Finally, strings are not pointers. A pointer can point to a string; a
pointer cannot be a string.

Yes. In my opinion, the null/empty string is this string: ""; the null
pointer is this value: NULL.
Yes -- but it's not a matter of opinion.

[news.motzarella.org was having problems, which seem to have been
cleared up; sorry if this appears twice.]

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Oct 8 '08 #15

P: n/a
"gg******@gmail.com" <gg******@gmail.comwrites:
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array.
If I understand right, then an appropriate initializer for y would be
something like

char *y[] = { "foo", "bar", "", "baz", "qux", "", "xyzzy", "plugh", 0 };
However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
Well, this may or may not be the case. But it's irrelevant to the
problem at hand. I think what you may be overlooking is that an empty
string is not represented by a NULL pointer (which can be got by
assigning the integer 0 to a pointer), but by a (non-NULL) pointer to
a null character ('\0'). (Or, if you prefer, an array of chars of
which the first is '\0'.) So if I write

char *s = "";

then the following expressions are all true:

s != NULL;
*s == '\0';
s[0] = '\0';

Based on this, you could also understand why

char t[30] = "hello";
strcat(t, s);

would leave t unchanged, while strcat(t, NULL) would crash. (If
you're confused, try writing your own version of strcat and see what
it would do in each case.)

In a sense, the point isn't whether the NULL pointer and the null
character '\0' are represented by the same bits (the C standard makes
no guarantee one way or the other). The issue is whether you're
looking at the pointer itself or the thing it points to.

This is complicated somewhat by the fact that some people write their
code in such a way that passing NULL where a string is expected has
the same effect as passing an empty string. But this is something
that they have to do explicitly. (You could modify your version of
strcat to do this if you want.) In the situation at hand, this is
exactly the opposite of what you want; the distinction between the two
is the information you need.
How then, can the function foo() determine the bounds of the array?
Knowing the bounds of the particular test case is not sufficient since
the actual test suite may have arrays of varying size.
Hopefully this discussion is enough of a hint. If not, post again.

By the way, if by "test" you mean this is part of an exam for a
course, don't forget to properly credit this post as a source of
information.
Oct 8 '08 #16

P: n/a

"Keith Thompson" <ks***@mib.orgwrote in message
news:ln************@nuthaus.mib.org...
"Bartc" <bc@freeuk.comwrites:
><vi******@gmail.comwrote in message
news:31**********************************@r37g200 0prr.googlegroups.com...
>>On Oct 8, 4:22 pm, "Bartc" <b...@freeuk.comwrote:
[...]
>>>Any empty string is not necessarily NULL.

An empty string is _never_ NULL.

I missed where the OP mentioned the null string "", and assumed that
NULL was also being used to signify an empty string.

However NULL to represent an empty string can be a useful technique
(although not recognised by standard functions), hence my comment.
[...]

Sure, you can use a null pointer to represent an empty string. You
can also use the number 42, or the string "this is an empty string",
to represent an empty string. You can use anything you like to
represent anything you like, as long as you're consistent about it.
I quite like this other quote in this thread:

<la************@siemens.comwrote in message
news:5q************@jones.homeip.net...
gg******@gmail.com <gg******@gmail.comwrote:
No. An empty string is like an empty box; a null pointer is no box at
all.
If you go to your drawer to get some socks, the absence of a drawer will
tell you you have no socks, just as well as an empty drawer. And you don't
have to open the drawer to find out.
>
But a null pointer *is not* an empty string, and it doesn't point to
an empty string. And, in my opinion, using a null pointer to
represent an empty string is a bad idea; it's too easy to accidentally
pass it to a function that doesn't know about your convention, and it
loses you the ability to distinguish between an empty string and the
absence of a string.
Well I used null pointers for empty strings before, outside of C. In C, that
would be problematic because standard functions tend to crash when you pass
null pointers. But I do still sometimes use null pointers this way, it just
needs some care.

--
Bartc

Oct 8 '08 #17

P: n/a
"gg******@gmail.com" wrote:
>
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.
Maybe "bunch of stuff" is that, but y is not. y is an array of
pointers to char, and those pointers also point to char arrays that
are not writeable. The arrays are strings, with a '\0' terminal
char. The last string is an empty string, and is used to mark the
end of the array.

Now consider what foo is. It appears, from your definition, to be
a function that returns void (i.e. nothing). It also requires a
parameter, x, which is a pointer to a char pointer.

Combining those things, the call to foo(y) cannot possibly do
anything.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 9 '08 #18

P: n/a
On 9 Oct, 01:27, CBFalconer <cbfalco...@yahoo.comwrote:
"ggngu...@gmail.com" wrote:
It's part of a test and I'm stumped. There is a function
void foo(char **x)
The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:
char *y[] = { /* bunch of stuff */ }
and calling
foo(y)
In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

Maybe "bunch of stuff" is that, but y is not. *y is an array of
pointers to char, and those pointers also point to char arrays that
are not writeable. *The arrays are strings, with a '\0' terminal
char. *The last string is an empty string, and is used to mark the
end of the array.

Now consider what foo is. *It appears, from your definition, to be
a function that returns void (i.e. nothing). *It also requires a
parameter, x, which is a pointer to a char pointer.

Combining those things, the call to foo(y) cannot possibly do
anything.

--
*[mail]: Chuck F (cbfalconer at maineline dot net)
*[page]: <http://cbfalconer.home.att.net>
* * * * * * Try the download section.- Hide quoted text -

- Show quoted text -
On 9 Oct, 01:27, CBFalconer <cbfalco...@yahoo.comwrote:

<snip>
Now consider what foo is. It appears, from your definition, to be
a function that returns void (i.e. nothing). It also requires a
parameter, x, which is a pointer to a char pointer.

Combining those things, the call to foo(y) cannot possibly do
anything.
i/o?

--
Nick Keighley
Oct 9 '08 #19

P: n/a
CBFalconer <cb********@yahoo.comwrites:
"gg******@gmail.com" wrote:
>>
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two strings
followed by a null string (""). However, the last triplet ends with an
integer 0. This seems that it's supposed to signify the end of the
array. However, it appears to me that 0 is the same binary value as
for the empty string (NUL, \0, whatever). So in effect, one cannot
test for it as a sentry value because it's actually the same as the
preceding triplets.

Maybe "bunch of stuff" is that, but y is not. y is an array of
pointers to char, and those pointers also point to char arrays that
are not writeable. The arrays are strings, with a '\0' terminal
char. The last string is an empty string, and is used to mark the
end of the array.

Now consider what foo is. It appears, from your definition, to be
a function that returns void (i.e. nothing). It also requires a
parameter, x, which is a pointer to a char pointer.

Combining those things, the call to foo(y) cannot possibly do
anything.
Um? Here are some possible definitions for foo that do things.

void foo(char **x) { x[3] = "Hi mom!"; }
void foo(char **x) { while (*x) puts(*x++); }
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }
void foo(char **x) { abort(); }

Oct 9 '08 #20

P: n/a
"Bartc" <bc@freeuk.comwrote:
"Keith Thompson" <ks***@mib.orgwrote in message
"Bartc" <bc@freeuk.comwrites:
However NULL to represent an empty string can be a useful technique
(although not recognised by standard functions), hence my comment.
Sure, you can use a null pointer to represent an empty string. You
can also use the number 42, or the string "this is an empty string",
to represent an empty string. You can use anything you like to
represent anything you like, as long as you're consistent about it.

I quite like this other quote in this thread:

<la************@siemens.comwrote in message
No. An empty string is like an empty box; a null pointer is no box at
all.

If you go to your drawer to get some socks, the absence of a drawer will
tell you you have no socks, just as well as an empty drawer. And you don't
have to open the drawer to find out.
I take it, then, that you've never worked with databases much. I assure
you, there is a world of difference between "We have no record of this
person" and "We have a record of this person, and his phone number field
is blank".
Basically, it's like asking how many legs a fish has, and how many legs
a null string has. In the first case, the answer is "none"; in the
second case, it's "What have you been smoking?".
But a null pointer *is not* an empty string, and it doesn't point to
an empty string. And, in my opinion, using a null pointer to
represent an empty string is a bad idea; it's too easy to accidentally
pass it to a function that doesn't know about your convention, and it
loses you the ability to distinguish between an empty string and the
absence of a string.

Well I used null pointers for empty strings before, outside of C. In C, that
would be problematic because standard functions tend to crash when you pass
null pointers. But I do still sometimes use null pointers this way, it just
needs some care.
No, it needs a situation where there is no difference between "doesn't
exist" and "is blank". Those situations are rarer than most people, even
most programmers with no database experience, believe.

Richard
Oct 9 '08 #21

P: n/a
Nate Eldredge wrote:
CBFalconer <cb********@yahoo.comwrites:
>"gg******@gmail.com" wrote:
>>>
It's part of a test and I'm stumped. There is a function

void foo(char **x)

The function signature is given and cannot be changed, so no passing
of other values. The test case involves defining this variable:

char *y[] = { /* bunch of stuff */ }

and calling

foo(y)

In the above, "bunch of stuff" is a series of triplets, two
strings followed by a null string (""). However, the last
triplet ends with an integer 0. This seems that it's supposed
to signify the end of the array. However, it appears to me that
0 is the same binary value as for the empty string (NUL, \0,
whatever). So in effect, one cannot test for it as a sentry
value because it's actually the same as the preceding triplets.

Maybe "bunch of stuff" is that, but y is not. y is an array of
pointers to char, and those pointers also point to char arrays
that are not writeable. The arrays are strings, with a '\0'
terminal char. The last string is an empty string, and is used
to mark the end of the array.

Now consider what foo is. It appears, from your definition, to
be a function that returns void (i.e. nothing). It also
requires a parameter, x, which is a pointer to a char pointer.

Combining those things, the call to foo(y) cannot possibly do
anything.

Um? Here are some possible definitions for foo that do things.

void foo(char **x) { x[3] = "Hi mom!"; }
void foo(char **x) { while (*x) puts(*x++); }
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }
void foo(char **x) { abort(); }
In other words you want to use globals and side-effects. I should
have specified further.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 9 '08 #22

P: n/a
On Oct 9, 12:31 pm, Nate Eldredge <n...@vulcan.lanwrote:

<snip>
Um? Here are some possible definitions for foo that do things.

void foo(char **x) { x[3] = "Hi mom!"; }
void foo(char **x) { while (*x) puts(*x++); }
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }
Well, longjmp takes two arguments...
Oct 9 '08 #23

P: n/a
On Oct 9, 6:25 pm, vipps...@gmail.com wrote:
On Oct 9, 12:31 pm, Nate Eldredge <n...@vulcan.lanwrote:

<snip>
Um? Here are some possible definitions for foo that do things.
void foo(char **x) { x[3] = "Hi mom!"; }
void foo(char **x) { while (*x) puts(*x++); }
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }

Well, longjmp takes two arguments...

Also, foo belongs in the programmers namespace, but EDOOFUS in the
implementations namespace, so the penultimate function can't work.
Oct 9 '08 #24

P: n/a
CBFalconer <cb********@yahoo.comwrites:
Nate Eldredge wrote:
>CBFalconer <cb********@yahoo.comwrites:
<snip>
>>Now consider what foo is. It appears, from your definition, to
be a function that returns void (i.e. nothing). It also
requires a parameter, x, which is a pointer to a char pointer.

Combining those things, the call to foo(y) cannot possibly do
anything.

Um? Here are some possible definitions for foo that do things.

void foo(char **x) { x[3] = "Hi mom!"; }
void foo(char **x) { while (*x) puts(*x++); }
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }
void foo(char **x) { abort(); }

In other words you want to use globals and side-effects. I should
have specified further.
Programming in C without side effects is almost impossible. Even if
we add the extra condition that all the x[i] point to unmodifiable
arrays (a restriction that Nate Eldredge's examples comply with) then
foo can still be useful. A clearer example might be

void sort_strings(char **x)
{
qsort(x, count_strings(x), sizeof *x, sptr_cmp);
}

where count_strings is the function the OP was originally asking
about and sptr_cmp compares strings when passed void *s that point at
pointers to these strings.

There are lots of useful functions with the same prototype as foo.

--
Ben.
Oct 9 '08 #25

P: n/a
On Oct 9, 11:26*am, vipps...@gmail.com wrote:
On Oct 9, 6:25 pm, vipps...@gmail.com wrote:
On Oct 9, 12:31 pm, Nate Eldredge <n...@vulcan.lanwrote:
<snip>
Um? *Here are some possible definitions for foo that do things.
void foo(char **x) { x[3] = "Hi mom!"; }
void foo(char **x) { while (*x) puts(*x++); }
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }
Well, longjmp takes two arguments...

Also, foo belongs in the programmers namespace, but EDOOFUS in the
implementations namespace, so the penultimate function can't work.
I think this is wrong. It can work. Either the implementation can
define EDOOFUS, which is just fine, or user code can define it if it
is not defined, also fine. It is generally a good idea NOT to start
your macros E[digit|uppercase] as it conflicts with a "future
direction" of a header. But the standard doesn't have language like
"reserved for any use", like leading __. But it is as far as I can
see legal and portable to put this in your code...

#include <errno.h>
#ifndef EDOOFUS
#define EDOOFUS 42
#endif

-David
Oct 9 '08 #26

P: n/a
Richard Bos <rl*@hoekstra-uitgeverij.nlwrote:
>
No, it needs a situation where there is no difference between "doesn't
exist" and "is blank". Those situations are rarer than most people, even
most programmers with no database experience, believe.
Even programmers *with* database experience. Oracle, for example,
continues to treat empty string values and nulls identically, although
they have warned (forever) that that could change some time in the
future. I've run into way too much code that depends on that
equivalence and doesn't work when ported to a different db that does
distinguish.
--
Larry Jones

They can make me do it, but they can't make me do it with dignity. -- Calvin
Oct 9 '08 #27

P: n/a
On Thu, 9 Oct 2008 08:50:24 -0700 (PDT),
David Resnick <ln********@gmail.comwrote:
On Oct 9, 11:26*am, vipps...@gmail.com wrote:
>On Oct 9, 6:25 pm, vipps...@gmail.com wrote:
On Oct 9, 12:31 pm, Nate Eldredge <n...@vulcan.lanwrote:
[snip]
void foo(char **x) { errno = EDOOFUS; }
void foo(char **x) { longjmp(somewhere); }
Well, longjmp takes two arguments...

Also, foo belongs in the programmers namespace, but EDOOFUS in the
implementations namespace, so the penultimate function can't work.

I think this is wrong. It can work. Either the implementation can
define EDOOFUS, which is just fine,
And, in fact, there are implementations that do exactly that.

Martien
--
|
Martien Verbruggen | Quick! Hire a teenager while they still know
| everything.
|
Oct 9 '08 #28

P: n/a
la************@siemens.com wrote:
Richard Bos <rl*@hoekstra-uitgeverij.nlwrote:

No, it needs a situation where there is no difference between "doesn't
exist" and "is blank". Those situations are rarer than most people, even
most programmers with no database experience, believe.

Even programmers *with* database experience. Oracle, for example,
continues to treat empty string values and nulls identically, although
they have warned (forever) that that could change some time in the
future.
Now, I'm not much of an SQL expert, certainly not compared to the people
at Oracle, but... isn't that illegal?

Richard
Oct 10 '08 #29

P: n/a
Richard Bos wrote:
la************@siemens.com wrote:
.... snip ...
>
>Even programmers *with* database experience. Oracle, for
example, continues to treat empty string values and nulls
identically, although they have warned (forever) that that
could change some time in the future.

Now, I'm not much of an SQL expert, certainly not compared to
the people at Oracle, but... isn't that illegal?
No, it isn't. First, they can certainly design their own functions
in any fashion they wish. Second, even if implementing C standard
functions, this is simply imposing a definition for 'undefined
behavior' on THEIR system.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 10 '08 #30

P: n/a
CBFalconer <cb********@yahoo.comwrites:
Richard Bos wrote:
>la************@siemens.com wrote:
... snip ...
>>
>>Even programmers *with* database experience. Oracle, for
example, continues to treat empty string values and nulls
identically, although they have warned (forever) that that
could change some time in the future.

Now, I'm not much of an SQL expert, certainly not compared to
the people at Oracle, but... isn't that illegal?

No, it isn't. First, they can certainly design their own functions
in any fashion they wish. Second, even if implementing C standard
functions, this is simply imposing a definition for 'undefined
behavior' on THEIR system.
I think Richard's question was about SQL, not about C.

In the interest of redirecting the question to a more appropriate
place, <http://en.wikipedia.org/wiki/Sql_nullseems to provide an
answer; see 9.1, "Common mistakes".

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Oct 10 '08 #31

This discussion thread is closed

Replies have been disabled for this discussion.