449,264 Members | 1,746 Online
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
30 Replies

 P: n/a

 P: n/a On Oct 8, 4:11 pm, "ggngu...@gmail.com"

 P: n/a On Oct 8, 4:22 pm, "Bartc"

 P: n/a "gg******@gmail.com"

 P: n/a On 8 okt, 15:11, "ggngu...@gmail.com" 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: > It's part of a test and I'm stumped. There is a functionvoid foo(char **x)The function signature is given and cannot be changed, so no passingof other values. The test case involves defining this variable:char *y[] = { /* bunch of stuff */ }and callingfoo(y)In the above, "bunch of stuff" is a series of triplets, two stringsfollowed by a null string (""). However, the last triplet ends with aninteger 0. This seems that it's supposed to signify the end of thearray. However, it appears to me that 0 is the same binary value asfor the empty string (NUL, \0, whatever). So in effect, one cannottest for it as a sentry value because it's actually the same as thepreceding 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 >{ "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 havetomark the end is 0, then use it and hope that on your system 0 will neverbea legal string pointer.) B?ll?cks. So eloquent. -- Bartc Oct 8 '08 #8

 P: n/a Bartc wrote: > On Oct 8, 4:22 pm, "Bartc" >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 makesense. 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 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 Email: -http://www. +rjh@ Google users: "Usenet is a strange place" - dmr 29 July 1999 Oct 8 '08 #11

 P: n/a gg******@gmail.com 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" On Oct 8, 4:22 pm, "Bartc" >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 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 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" But a null pointer *is not* an empty string, and it doesn't point toan empty string. And, in my opinion, using a null pointer torepresent an empty string is a bad idea; it's too easy to accidentallypass it to a function that doesn't know about your convention, and itloses you the ability to distinguish between an empty string and theabsence of a string.Finally, strings are not pointers. A pointer can point to a string; apointer 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 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"

 P: n/a "Keith Thompson" >On Oct 8, 4:22 pm, "Bartc" >>Any empty string is not necessarily NULL.An empty string is _never_ NULL. I missed where the OP mentioned the null string "", and assumed thatNULL 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: 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]: Try the download section. Oct 9 '08 #18

 P: n/a On 9 Oct, 01:27, CBFalconer * * * * * * Try the download section.- Hide quoted text - - Show quoted text - On 9 Oct, 01:27, CBFalconer 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 >It's part of a test and I'm stumped. There is a functionvoid foo(char **x)The function signature is given and cannot be changed, so no passingof other values. The test case involves defining this variable:char *y[] = { /* bunch of stuff */ }and callingfoo(y)In the above, "bunch of stuff" is a series of triplets, two stringsfollowed by a null string (""). However, the last triplet ends with aninteger 0. This seems that it's supposed to signify the end of thearray. However, it appears to me that 0 is the same binary value asfor the empty string (NUL, \0, whatever). So in effect, one cannottest for it as a sentry value because it's actually the same as thepreceding 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"

 P: n/a Nate Eldredge wrote: CBFalconer "gg******@gmail.com" wrote: >>>It's part of a test and I'm stumped. There is a functionvoid foo(char **x)The function signature is given and cannot be changed, so no passingof other values. The test case involves defining this variable:char *y[] = { /* bunch of stuff */ }and callingfoo(y)In the above, "bunch of stuff" is a series of triplets, twostrings followed by a null string (""). However, the lasttriplet ends with an integer 0. This seems that it's supposedto signify the end of the array. However, it appears to me that0 is the same binary value as for the empty string (NUL, \0,whatever). So in effect, one cannot test for it as a sentryvalue because it's actually the same as the preceding triplets. Maybe "bunch of stuff" is that, but y is not. y is an array ofpointers to char, and those pointers also point to char arraysthat are not writeable. The arrays are strings, with a '\0'terminal char. The last string is an empty string, and is usedto mark the end of the array.Now consider what foo is. It appears, from your definition, tobe a function that returns void (i.e. nothing). It alsorequires a parameter, x, which is a pointer to a char pointer.Combining those things, the call to foo(y) cannot possibly doanything. 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]: Try the download section. Oct 9 '08 #22

 P: n/a On Oct 9, 12:31 pm, Nate Eldredge 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 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 CBFalconer >>Now consider what foo is. It appears, from your definition, tobe a function that returns void (i.e. nothing). It alsorequires a parameter, x, which is a pointer to a char pointer.Combining those things, the call to foo(y) cannot possibly doanything. 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 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 #ifndef EDOOFUS #define EDOOFUS 42 #endif -David Oct 9 '08 #26

 P: n/a Richard Bos 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 On Oct 9, 6:25 pm, vipps...@gmail.com wrote: On Oct 9, 12:31 pm, Nate Eldredge

 P: n/a la************@siemens.com wrote: Richard Bos

 P: n/a Richard Bos wrote: la************@siemens.com wrote: .... snip ... > >Even programmers *with* database experience. Oracle, forexample, continues to treat empty string values and nullsidentically, although they have warned (forever) that thatcould 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]: Try the download section. Oct 10 '08 #30

 P: n/a CBFalconer la************@siemens.com wrote: ... snip ... >> >>Even programmers *with* database experience. Oracle, forexample, continues to treat empty string values and nullsidentically, although they have warned (forever) that thatcould change some time in the future. Now, I'm not much of an SQL expert, certainly not compared tothe 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, Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Oct 10 '08 #31