determining size of array of chars

D

dehantonio

I start from the following situation:

const char *LineMenu[] = {"ls", "pwd", "cd");
#define MENUSIZE 3

int somefunction(char* inputbuffer) {

}
 
D

dehantonio

Please disregard my previous post, I pressed "submit" by mistake, I do
not know how it could happen that the focus was on the wrong window.

I start from the following situation:

const char *LineMenu[] = {"ls", "pwd", "cd");
#define MENUSIZE 3

int somefunction(char* inputbuffer) {
int idx;
for (idx = 0; idx < MENUSIZE; idx++) {
if (strstr(inputbuffer, LineMenu[idx])) {
return idx;
}
}
//not found:
return -1;
}


Now, I would like to get rid of the MENUSIZE define. For example, if I
add more commands to LineMenu array, is there a way of dynamically
check it's size in the for cycle?
I want to avoid that I add a new command to LineMenu and I forget to
update MENUSIZE, or, in case LineMenu is huge, counting the array's
cells is not practical.
Thank you.
 
D

dehantonio

This is an array of strings, not chars. A trick to get the length of an array A
is
        (sizeof A/sizeof A[0])
provided A is actually an array and not a pointer.
In other words, it will not work with my code. Correct?
Said that, the answer is there is no way to get rid of the define in
my code?
 
F

Francesco S. Carta

This is an array of strings, not chars. A trick to get the length of an array A
is
(sizeof A/sizeof A[0])
provided A is actually an array and not a pointer.
In other words, it will not work with my code. Correct?
Said that, the answer is there is no way to get rid of the define in
my code?

It seems to work - caveat, I'm just starting with C, so cope with any
error of mine (but point them out if any, please):

#include <stdlib.h>
#include <string.h>

const char *LineMenu[] = {"ls", "pwd", "cd"};

int somefunction(char* inputbuffer) {
int idx;

const int menusize = sizeof(LineMenu) / sizeof(LineMenu[0]);

for (idx = 0; idx < menusize; idx++) {
if (strstr(inputbuffer, LineMenu[idx])) {
return idx;
}
}
//not found:
return -1;
}

int main(void) {
printf("%d\n", somefunction("cd"));
return 0;
}
 
M

Mark Bluemel

dehantonio said:
This is an array of strings, not chars. A trick to get the length of an array A
is
(sizeof A/sizeof A[0])
provided A is actually an array and not a pointer.
In other words, it will not work with my code. Correct?

Incorrect.

"China Blue" first of all points out an inaccuracy in your subject line
- the array isn't an array of chars, it's an array of pointers to char.

He/She then points out the canonical standard way of determining the
number of elements in an array. (This is an FAQ - see http://c-faq.com/,
especially FAQ 6.23).

Here's a demo :-

$ cat x.c
#include <stdlib.h>
#include <stdio.h>
int main(void) {
const char *LineMenu[] = {"ls", "pwd", "cd"};
printf("Menu has %d items\n",
(int)(sizeof(LineMenu)/sizeof(LineMenu[0])));
}

$ make x
cc x.c -o x

$ ./x
Menu has 3 items
 
D

David Resnick

This is an array of strings, not chars. A trick to get the length of an array A
is
         (sizeof A/sizeof A[0])
provided A is actually an array and not a pointer.
In other words, it will not work with my code. Correct?
Said that, the answer is there is no way to get rid of the define in
my code?

It seems to work - caveat, I'm just starting with C, so cope with any
error of mine (but point them out if any, please):

#include <stdlib.h>
#include <string.h>

const char *LineMenu[] = {"ls", "pwd", "cd"};

int somefunction(char* inputbuffer) {
     int idx;

     const int menusize = sizeof(LineMenu) / sizeof(LineMenu[0]);

     for (idx = 0; idx < menusize; idx++) {
         if (strstr(inputbuffer, LineMenu[idx])) {
             return idx;
         }
     }
     //not found:
     return -1;

}

int main(void) {
     printf("%d\n", somefunction("cd"));
     return 0;

}

This approach works as long as the array declaration is in scope.
Common ways to handle this if the array is NOT in scope -- which is
quite often the case -- include:
1) Pass around the array size. Either as a separate parameter, or
have a struct whose members are the array and its size.
2) Put a sentinel in the array. e.g. assuming that you'd never
actually want NULL pointer in your menu, put one at the end. You can
then process the array until the NULL is found and know you are done.

-David
 
A

August Karlstrom

I start from the following situation:

const char *LineMenu[] = {"ls", "pwd", "cd");
#define MENUSIZE 3

int somefunction(char* inputbuffer) {

}

Hint: Count the number of characters in `inputbuffer' until you reach
the string terminator '\0' (or just use the library function `strlen').


/August
 
M

Malcolm McLean

const char *LineMenu[] = {"ls", "pwd", "cd");
#define MENUSIZE 3

Now, I would like to get rid of the MENUSIZE define.
One solution is to add a null sentinel to the list of strings

const char *LineMenu[] = {"ls", "pwd", "cd", 0};

This is used quite a bit in terminating string arrays.

However I wouldn't be frightened of passing about a length parameter.
Most arrays don't have a convenient value to use as a sentinel, and
you can't obtain a size froma pointer, so this is the most common
method used in C.
 
F

Francesco S. Carta

On 23 Ago, 16:51, You're talkin 'bout China Blue Grove
This is an array of strings, not chars. A trick to get the length of an array A
is
(sizeof A/sizeof A[0])
provided A is actually an array and not a pointer.
In other words, it will not work with my code. Correct?
Said that, the answer is there is no way to get rid of the define in
my code?

It seems to work - caveat, I'm just starting with C, so cope with any
error of mine (but point them out if any, please):

#include<stdlib.h>
#include<string.h>

const char *LineMenu[] = {"ls", "pwd", "cd"};

int somefunction(char* inputbuffer) {
int idx;

const int menusize = sizeof(LineMenu) / sizeof(LineMenu[0]);

for (idx = 0; idx< menusize; idx++) {
if (strstr(inputbuffer, LineMenu[idx])) {
return idx;
}
}
//not found:
return -1;

}

int main(void) {
printf("%d\n", somefunction("cd"));
return 0;

}

This approach works as long as the array declaration is in scope.
Common ways to handle this if the array is NOT in scope -- which is
quite often the case -- include:

Thank you for your notes David, I've fiddled a bit with the OP code and...
1) Pass around the array size. Either as a separate parameter, or
have a struct whose members are the array and its size.

....I have no idea about how to implement the above, while...
2) Put a sentinel in the array. e.g. assuming that you'd never
actually want NULL pointer in your menu, put one at the end. You can
then process the array until the NULL is found and know you are done.

....I have modified the code to follow the above, and it seems to work
fine, please point out anything that could make your eyebrows lift:

#include <stdlib.h>
#include <string.h>

const char** Menu(void) {
static const char* LineMenu[] = {"ls", "pwd", "cd", NULL};
return LineMenu;
}

int MenuSize(void) {
static int size = 0;
if(size == 0) {
const char** p = Menu();
while(p[size] != NULL) ++size;
}
return size;
}

int somefunction(char* inputbuffer) {
const int menusize = MenuSize();
const char** menu = Menu();
int idx;
for (idx = 0; idx < menusize; ++idx) {
if (strstr(inputbuffer, menu[idx])) {
return idx;
}
}
return -1;
}

int main(void) {
printf("somefunction(%s) == %d\n", "cd", somefunction("cd"));
return 0;
}
 
K

Keith Thompson

You're talkin 'bout China Blue Grove said:
dehantonio said:
I start from the following situation:

const char *LineMenu[] = {"ls", "pwd", "cd");
#define MENUSIZE 3

This is an array of strings, not chars. A trick to get the length of an array A
is
(sizeof A/sizeof A[0])
provided A is actually an array and not a pointer.

No, it's not an array of strings. In fact, there is no such thing
as an "array of strings" in C. A string is a data *format*, not a
data *type*. Specifically, it's defined as "a contiguous sequence
of characters terminated by and including the first null character"
(C99 7.1.1p1).

LineMenu is an array of *pointers*, each of which happens to point to
(the first character of) a string.

And yes, the sizeof trick above will work just fine. See the
comp.lang.c FAQ, <http://www.c-faq.com/>, question 6.23. Read the
rest of section 6 while you're in the neighborhood.
 
A

Alexander Wieck

const char *LineMenu[] = {"ls", "pwd", "cd");

same as:
char *LineMenu[] = {"ls", "pwd", "cd");
 
A

Andrey Tarasevich

dehantonio said:
I start from the following situation:

const char *LineMenu[] = {"ls", "pwd", "cd");
#define MENUSIZE 3

int somefunction(char* inputbuffer) {

}

And???

The subject of your post is not really connected to its contents.

What is your question, if there's any?
 
A

Alexander Wieck

The compiler produce the same code with and without const, or not?
This is deciding for me.
A compiler-warning on changing the const object is not guaranteed, therefore
this const is useless for me. A good lint ever find this problem.
 
S

Seebs

The compiler produce the same code with and without const, or not?
Sometimes!

A compiler-warning on changing the const object is not guaranteed, therefore
this const is useless for me.

Imperfect is not the same as useless.

-s
 
A

Andrey Tarasevich

Alexander said:
The compiler produce the same code with and without const, or not?
This is deciding for me.

That's strange, since "compiler produce the same code" is totally
useless criterion without any practical or theoretical uses. It
certainly cannot be used to support any "same as" assertions.

That way one can arrive to conclusion that `int` is the same as `long`
since on some platform they saw a compiler that produces the same code
for both. Or, `char` and `signed char` for another example.
 
K

Keith Thompson

Alexander Wieck said:
The compiler produce the same code with and without const, or not?
This is deciding for me.
A compiler-warning on changing the const object is not guaranteed, therefore
this const is useless for me. A good lint ever find this problem.

Please include enough context so that a reader can make some sense of
your followup without having seen the previous article. See most of the
articles in this newsgroup.

Assuming a conforming compiler, and assuming the code doesn't
deliberately bypass constness by pointer casting or type-punning,
yes, a diagnostic *is* guaranteed. And if nothing else, "const"
can be valuable as documentation.
 
D

dehantonio

No, it's not an array of strings.  In fact, there is no such thing
as an "array of strings" in C.  A string is a data *format*, not a
data *type*.  Specifically, it's defined as "a contiguous sequence
of characters terminated by and including the first null character"
(C99 7.1.1p1).

LineMenu is an array of *pointers*, each of which happens to point to
(the first character of) a string.

And yes, the sizeof trick above will work just fine.  See the
comp.lang.c FAQ, <http://www.c-faq.com/>, question 6.23.  Read the
rest of section 6 while you're in the neighborhood.
I understand. I also tried the code on a PC and it works.
However, question 6.23 is a bit different, since every element has the
same size (int). In this case, I am declaring an array of pointers to
elements that do not have the same lenght: "pwd" is longer than "cd".
If the trik works, it means that the memory is allocated like this:
Byte - content
01 - l
02 - s
03 - \0
04 - ?
05 - p
06 - w
07 - d
08 - \0
09 - c
0A - d
0B - \0
0C - ?

Now, the question: is this behaviour a standard, or any compiler could
decide whether to skip or not bytes 04 and 0C?
 
S

Seebs

I understand. I also tried the code on a PC and it works.
However, question 6.23 is a bit different, since every element has the
same size (int). In this case, I am declaring an array of pointers to
elements that do not have the same lenght: "pwd" is longer than "cd".

So what?

The *POINTERS* all have the same length.

There is no "trick". The array is an array of pointers, and we have no
information at all about how the things pointed to might be stored in
relation to each other.

Now, the question: is this behaviour a standard, or any compiler could
decide whether to skip or not bytes 04 and 0C?

The behavior doesn't even exist. You don't understand what a pointer is,
apparently.

The array of pointers does not hold the strings. It holds representations
of where the strings are. The sizes of the strings are irrelevant.

What you might find more interesting would be:

char example[2][6] = {
"hello", "a"
};

This is necessarily stored in memory as
h e l l o \0 a \0 \0 \0 \0 \0

-s
 
P

Peter Nilsson

dehantonio said:
I understand. I also tried the code on a PC and it works.
However, question 6.23 is a bit different, since every
element has the same size (int). In this case, I am
declaring an array of pointers to elements that do not
have the same lenght:

Nevertheless, the pointers (to char) all have the same
size.
"pwd" is longer than "cd".
If the trik works, it means that the memory is allocated
like this:
Byte - content
01   - l
02   - s
03   - \0
04   - ?
05   - p
06   - w
07   - d
08   - \0
09   - c
0A   - d
0B   - \0
0C   - ?

Possibly...

const char *LineMenu[] = {"ls", "pwd", "cd"};

....is handled like...

/* actually, these may or may not be const qualified */
const char __string_1[3] = { 'l', 's', 0 };
const char __string_2[4] = { 'p', 'w', 'd', 0 };
const char __string_3[3] = { 'c', 'd', 0 };

const char * LineMenu[3] =
{ &__string_1[0], &__string_2[0], &__string_3[0] };

The __string_N objects may or may not be allocated
sequencially, but there's no point knowing or caring
about that. The pointers in LineMenu will be allocated
sequencially, and they will all have the same size.

I dare say you're being confused by the fact that a
string literal can be used as an initialisor for both
an array and a pointer to char.
 
D

dehantonio

So what?

The *POINTERS* all have the same length.

Why?


The behavior doesn't even exist.  You don't understand what a pointer is,
apparently.

Possibly my understanding is not very clear, that's why I am asking
here.
The array of pointers does not hold the strings.  It holds representations
of where the strings are.  The sizes of the strings are irrelevant.

What you might find more interesting would be:

        char example[2][6] = {
                "hello", "a"
        };

This is necessarily stored in memory as
        h e l l o \0 a \0 \0 \0 \0 \0

This example is trivial.
It is less trivial to understand why, if I declare
const char *example[] = {
"hello", "a"
};
then I find that sizeof(example[0]) is 5 and sizeof(example[1]) is
still 5.
Why? This result lead me to think that in this case too the memory is

h e l l o \0 a \0 \0 \0 \0 \0

exactly the same of your example.
In other words, the compiler has to assign to the pointer the maximum
size, correct?
 

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

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top