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

simple array question

P: n/a
Hi,

I am trying to pass a function an array of strings, but I am having trouble
getting the indexing to index the strings rather than the individual
characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic number
here*/

Then try to access the elements with
func(array+i, array+result); /* func(char *, char
*) */
the array+i is indexing through the first string, rather than through the
array of strings.

I dont understand why array+1 = "ne" and not "two"

can anyone help me with this please?

Regards

Michael

Aug 18 '06 #1
Share this Question
Share on Google+
24 Replies


P: n/a
Michael schrieb:
Hi,

I am trying to pass a function an array of strings, but I am having trouble
getting the indexing to index the strings rather than the individual
characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic number
here*/
Passing *stringArray is equivalent to passing stringArray[0]
which is the start address of a string containing "one".
Then try to access the elements with
func(array+i, array+result); /* func(char *, char
*) */
the array+i is indexing through the first string, rather than through the
array of strings.
If you posted actual code, then I would not have to guess whether
func is supposed to be CompareStringArray() even though the number
of parameters changed.

The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
>
I dont understand why array+1 = "ne" and not "two"
Probably because you passed the address of "one"...
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Aug 18 '06 #2

P: n/a
"Michael" <mi*********@yahoo.comwrites:
I am trying to pass a function an array of strings, but I am having trouble
getting the indexing to index the strings rather than the individual
characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};
That's an array of pointers.

A "string" is really more of a data format that a data type. It's
defined by the standard as "a contiguous sequence of characters
terminated by and including the first null character".

What you've declared is an array of pointers to strings (where a
"pointer to a string" is defined as "a pointer to its initial (lowest
addressed) character").
When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic number
here*/
*stringArray is a value of type char*. It points to the string "one".
Then try to access the elements with
func(array+i, array+result); /* func(char *, char
*) */
the array+i is indexing through the first string, rather than through the
array of strings.
Right. When you increment a pointer to FOO, the result points to the
next FOO in memory (assuming there is one). In this case, you're
incrementing a pointer to char (pointing to the 'o' of "one" and
getting a pointer to the next char (pointig to the 'n' of "one").

Your CompareStringArray function needs to have a parameter of type
char**, and you need to pass it stringArray, not *stringArray.

And you need to read section 6 of the comp.lang.c FAQ,
<http://www.c-faq.com/>.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Aug 18 '06 #3

P: n/a
Michael wrote:
>
I am trying to pass a function an array of strings, but I am
having trouble getting the indexing to index the strings rather
than the individual characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a
magic number here*/

Then try to access the elements with
func(array+i, array+result); /* func(char *, char *) */
the array+i is indexing through the first string, rather than
through the array of strings.

I dont understand why array+1 = "ne" and not "two"

can anyone help me with this please?
You are not keeping the types of things clear. Keeping your
declaration only, if we then pass that to a function:

foo(stringarray)

the function would be declared as:

foo(char **arr)
or
foo(char *arr[])

the point being that what foo sees is an array of pointers to char,
identified by a pointer to the first of those, i.e. the char **.
You can now get pointers to the various strings by dereferencing
arr[i] for some i from 0 to the number available.

foo(char **arr) {
char *p;
int i;

for (i = 0; i < 3; i++) {
p = arr[i];
/* operate on p to access the string */
/* which is read-only for your declaration */
puts(p); /* for example */
}
}

It would be well to have the original declaration mark its own
boundary by terminating it with a NULL, ie:

char *stringArray[] = {"one", "two", "three", "a", NULL};

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943

Aug 18 '06 #4

P: n/a

"Michael Mair" <Mi**********@invalid.invalidwrote in message
news:4k************@individual.net...
Michael schrieb:
>Hi,

I am trying to pass a function an array of strings, but I am having
trouble getting the indexing to index the strings rather than the
individual characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic
number here*/

Passing *stringArray is equivalent to passing stringArray[0]
which is the start address of a string containing "one".
>Then try to access the elements with
func(array+i, array+result); /* func(char *,
char *) */
the array+i is indexing through the first string, rather than through the
array of strings.

If you posted actual code, then I would not have to guess whether
func is supposed to be CompareStringArray() even though the number
of parameters changed.

The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
>>
I dont understand why array+1 = "ne" and not "two"

Probably because you passed the address of "one"...
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray in my
function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer without a
cast".
I know I have some magic numbers and stuff, I'm really just trying to sort
out the array stuff though.

int main(){
char *stringArray[] = {"one","two","three","four","five"};
int smallest;
int largest;

smallest = CompareStringArray(*stringArray, 4, min);
largest = CompareStringArray(*stringArray, 4, max);

if(smallest -1){
printf("\nsmallest is %s at position
%d",stringArray[smallest], smallest);
}else {
printf("\nempty array");
}
if(largest -1){
printf("\nlargest is %s at position
%d",stringArray[largest], largest);
}else {
printf("\nempty array");
}

fgetc(stdin);
return 0;
}

int max(char *string1, char *string2){
int result = FALSE;

if(strlen(string1) strlen(string2)){
result = TRUE;
}

return result;
}

int min(char *string1, char *string2){
int result = FALSE;

if(strlen(string1) < strlen(string2)){
result = TRUE;
}

return result;
}

int CompareStringArray(char *array, int size, int (*func)(char*, char*)){
int i;
int result;

if(!strlen(array)){
result = 0; /*arbitrary starting point
for result*/
for(i = 0; i < size; i++){
if(func(array+i, array+result)){ /*check if current is longer
than longest found yet*/
result = i;
}
}
} else {
result = -1; /*zero length array*/
}
return result;
}
Aug 18 '06 #5

P: n/a
Michael wrote:
>
"Michael Mair" <Mi**********@invalid.invalidwrote in message
news:4k************@individual.net...
Michael schrieb:
Hi,

I am trying to pass a function an array of strings, but I am having
trouble getting the indexing to index the strings rather than the
individual characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic
number here*/
Passing *stringArray is equivalent to passing stringArray[0]
which is the start address of a string containing "one".
Then try to access the elements with
func(array+i, array+result); /* func(char *,
char *) */
the array+i is indexing through the first string, rather than through the
array of strings.
If you posted actual code, then I would not have to guess whether
func is supposed to be CompareStringArray() even though the number
of parameters changed.

The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
>
I dont understand why array+1 = "ne" and not "two"
Probably because you passed the address of "one"...
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray in my
function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer without a
cast".
I know I have some magic numbers and stuff, I'm really just trying to sort
out the array stuff though.

int main(){
char *stringArray[] = {"one","two","three","four","five"};
int smallest;
int largest;

smallest = CompareStringArray(*stringArray, 4, min);
largest = CompareStringArray(*stringArray, 4, max);

if(smallest -1){
printf("\nsmallest is %s at position
%d",stringArray[smallest], smallest);
}else {
printf("\nempty array");
}
if(largest -1){
printf("\nlargest is %s at position
%d",stringArray[largest], largest);
}else {
printf("\nempty array");
}

fgetc(stdin);
return 0;
}

int max(char *string1, char *string2){
int result = FALSE;

if(strlen(string1) strlen(string2)){
result = TRUE;
}

return result;
}

int min(char *string1, char *string2){
int result = FALSE;

if(strlen(string1) < strlen(string2)){
result = TRUE;
}

return result;
}

int CompareStringArray(char *array, int size, int (*func)(char*, char*)){
int i;
int result;

if(!strlen(array)){
result = 0; /*arbitrary starting point
for result*/
for(i = 0; i < size; i++){
if(func(array+i, array+result)){ /*check if current is longer
than longest found yet*/
result = i;
}
}
} else {
result = -1; /*zero length array*/
}
return result;
}
/* BEGIN ptr_sort.c */
/*
** lencomp() compares pointers to strings,
** according to string length.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SORT_FUNCTIONS { \
no_sort, "This is the original order of the test array:",\
si_sort, "Stable insertionsort:", \
s38sort, "Nonstable Shellsort, four is after " \
"nine, and eight is before three:", \
q_sort, "Standard library qsort, " \
"unspecified ordering of equal keys:", \
}
#define NUMBERS { \
{"one"},{ "two"},{"three"},{"four"},{"five"}, \
{"six"},{"seven"},{"eight"},{"nine"},{ "ten"}, \
}
#define GT(A, B) (lencomp((A), (B)) 0)
#define NMEMB (sizeof numbers / sizeof *numbers)
#define SORTS (sizeof s_F / sizeof *s_F)
#define str(s) # s
#define xstr(s) str(s)
#define E_TYPE char *

typedef E_TYPE e_type;

int lencomp(const void *, const void *);
void no_sort(e_type *, size_t);
void si_sort(e_type *, size_t);
void s38sort(e_type *, size_t);
void q_sort(e_type *, size_t);

int main(void)
{
size_t element, sort;
struct sf {
void (*function)(e_type *, size_t);
const char *description;
} s_F[] = SORT_FUNCTIONS;
const e_type numbers[] = NUMBERS;
e_type copy[NMEMB];

puts("/* BEGIN output from ptr_sort.c */\n");
puts("Arrays of type " xstr(E_TYPE)
",\nare being sorted by string length.");
for (sort = 0; sort != SORTS; ++sort) {
putchar('\n');
puts(s_F[sort].description);
memcpy(copy, numbers, sizeof copy);
s_F[sort].function(copy, NMEMB);
for (element = 0; element != NMEMB; ++element) {
puts(copy[element]);
}
}
puts("\n/* END output from ptr_sort.c */");
return 0;
}

int lencomp(const void *a, const void *b)
{
const size_t a_len = strlen(*(e_type *)a);
const size_t b_len = strlen(*(e_type *)b);

return b_len a_len ? -1 : a_len != b_len;
}

void no_sort(e_type *array, size_t nmemb)
{
array, nmemb;
}

void si_sort(e_type *array, size_t nmemb)
{
e_type temp, *base, *low, *high;

if (nmemb-- 1) {
base = array;
do {
low = array++;
if (GT(low, array)) {
high = array;
temp = *high;
do {
*high-- = *low;
if (low == base) {
break;
}
--low;
} while (GT(low, &temp));
*high = temp;
}
} while (--nmemb != 0);
}
}

void s38sort(e_type *array, size_t nmemb)
{
e_type temp, *i, *j, *k, *after;

after = array + nmemb;
if (nmemb (size_t)-1 / 3) {
nmemb /= 3;
}
do {
for (i = array + nmemb; after != i; ++i) {
j = i - nmemb;
if (GT(j, i)) {
k = i;
temp = *k;
do {
*k = *j;
k = j;
if (nmemb + array j) {
break;
}
j -= nmemb;
} while (GT(j, &temp));
*k = temp;
}
}
nmemb = nmemb != 2 ? 3 * nmemb / 8 : 1;
} while (nmemb != 0);
}

void q_sort(e_type *array, size_t nmemb)
{
qsort(array, nmemb, sizeof *array, lencomp);
}

/* END ptr_sort.c */
--
pete
Aug 18 '06 #6

P: n/a
Michael wrote:
"Michael Mair" <Mi**********@invalid.invalidwrote in message
.... snip ...
>>
The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
REMEMBER THE ABOVE
... snip ...
>
Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray in my
function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer without a
cast".
And remember that too.

The following is only what I had to do to your source to make it
compile (not run). The changes consist of proper formatting (via
indent), judicious insertion of the 'const' keyword, and addition
of the #includes and #defines at the start. In addition I had to
move the function definitions so that functions are defined before
use. The source line length is limited to something that will
avoid wrapping on most newsreaders, and the 'void' is added to the
definition of main.

You are still using some nominally illegal variable names, i.e.
"stri....". These, among others, are reserved for the
implementation and can nip you in the butt.

With the above 'remember's and the cleaned up compilable source,
see if you can figure out the basic problems that remain.

#include <stdio.h>
#include <string.h>

#define FALSE (0)
#define TRUE (1)

/* ----------------------- */

int max(const char *string1, const char *string2)
{
int result = FALSE;

if (strlen(string1) strlen(string2)) {
result = TRUE;
}
return result;
}

/* ----------------------- */

int min(const char *string1, const char *string2)
{
int result = FALSE;

if (strlen(string1) < strlen(string2)) {
result = TRUE;
}
return result;
}

/* ----------------------- */

int CompareStringArray(const char *array, int size,
int (*func)(const char *, const char *))
{
int i;
int result;

if (!strlen(array)) {
result = 0; /* arbitrary starting point for result */
for (i = 0; i < size; i++) {
if (func(array + i, array + result)) {
/* check if current is longer than longest found yet */
result = i;
}
}
}
else {
result = -1; /* zero length array */
}
return result;
}

/* ----------------------- */

int main(void)
{
const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
int smallest;
int largest;

smallest = CompareStringArray(*stringArray, 4, min);
largest = CompareStringArray(*stringArray, 4, max);

if (smallest -1) {
printf("\nsmallest is %s at position %d",
stringArray[smallest], smallest);
}
else {
printf("\nempty array");
}
if (largest -1) {
printf("\nlargest is %s at position %d",
stringArray[largest], largest);
}
else {
printf("\nempty array");
}
fgetc(stdin);
return 0;
}

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943
Aug 18 '06 #7

P: n/a
Michael wrote:
Hi,

I am trying to pass a function an array of strings, but I am having trouble
getting the indexing to index the strings rather than the individual
characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic number
here*/

Then try to access the elements with
func(array+i, array+result); /* func(char *, char
*) */
the array+i is indexing through the first string, rather than through the
array of strings.

I dont understand why array+1 = "ne" and not "two"

can anyone help me with this please?
Your definition of stringArray is 'array of pointer to char'. Expressing
stringArray will give you the first pointer. *stringArray is the first
character of the first string. Think about it.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Aug 18 '06 #8

P: n/a

"CBFalconer" <cb********@yahoo.comwrote in message
news:44***************@yahoo.com...
Michael wrote:
>"Michael Mair" <Mi**********@invalid.invalidwrote in message
... snip ...
>>>
The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
REMEMBER THE ABOVE
... snip ...
>>
Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray in my
function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer without a
cast".

And remember that too.

The following is only what I had to do to your source to make it
compile (not run). The changes consist of proper formatting (via
indent), judicious insertion of the 'const' keyword, and addition
of the #includes and #defines at the start. In addition I had to
move the function definitions so that functions are defined before
use. The source line length is limited to something that will
avoid wrapping on most newsreaders, and the 'void' is added to the
definition of main.

You are still using some nominally illegal variable names, i.e.
"stri....". These, among others, are reserved for the
implementation and can nip you in the butt.

With the above 'remember's and the cleaned up compilable source,
see if you can figure out the basic problems that remain.

#include <stdio.h>
#include <string.h>

#define FALSE (0)
#define TRUE (1)

/* ----------------------- */

int max(const char *string1, const char *string2)
{
int result = FALSE;

if (strlen(string1) strlen(string2)) {
result = TRUE;
}
return result;
}

/* ----------------------- */

int min(const char *string1, const char *string2)
{
int result = FALSE;

if (strlen(string1) < strlen(string2)) {
result = TRUE;
}
return result;
}

/* ----------------------- */

int CompareStringArray(const char *array, int size,
int (*func)(const char *, const char *))
{
int i;
int result;

if (!strlen(array)) {
result = 0; /* arbitrary starting point for result */
for (i = 0; i < size; i++) {
if (func(array + i, array + result)) {
/* check if current is longer than longest found yet */
result = i;
}
}
}
else {
result = -1; /* zero length array */
}
return result;
}

/* ----------------------- */

int main(void)
{
const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
int smallest;
int largest;

smallest = CompareStringArray(*stringArray, 4, min);
largest = CompareStringArray(*stringArray, 4, max);

if (smallest -1) {
printf("\nsmallest is %s at position %d",
stringArray[smallest], smallest);
}
else {
printf("\nempty array");
}
if (largest -1) {
printf("\nlargest is %s at position %d",
stringArray[largest], largest);
}
else {
printf("\nempty array");
}
fgetc(stdin);
return 0;
}

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943

Thanks for the help, but you don't seem to have changed anything about the
way the array is passed or handled, which is where my problem is.
The array+i still indexes through the first element, rather than through the
array of strings.
I know this is to do with the way I am passing the array, but I cant figure
out what concept I have misunderstood.

const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
so
stringArray[0][0] = 'o'
stringArray[0][1] = 'n'
stringArray[0][2] = 'e'
correct?

so
stringArray[0] = 'one'
correct?

so
*stringArray = 'one'
correct?

Regards

Michael
Aug 18 '06 #9

P: n/a
CBFalconer wrote:

<snipped>
You are still using some nominally illegal variable names, i.e.
"stri....". These, among others, are reserved for the
implementation and can nip you in the butt.
AFAIK, "str..." is reserved for function names. Variable
names starting with "str..." are safe.

goose,
Aug 19 '06 #10

P: n/a
Michael wrote:
"CBFalconer" <cb********@yahoo.comwrote in message
>Michael wrote:
>>"Michael Mair" <Mi**********@invalid.invalidwrote in message
... snip ...
>>>>
The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
REMEMBER THE ABOVE
... snip ...
>>>
Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray
in my function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer
without a cast".

And remember that too.
.... snip ...
>
Thanks for the help, but you don't seem to have changed anything
about the way the array is passed or handled, which is where my
problem is. The array+i still indexes through the first element,
rather than through the array of strings.
I know this is to do with the way I am passing the array, but I
cant figure out what concept I have misunderstood.

const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
so
stringArray[0][0] = 'o'
stringArray[0][1] = 'n'
stringArray[0][2] = 'e'
correct?

so
stringArray[0] = 'one'
correct?
No. stringArray[0] is a pointer to the char array "one\0", which
in turn is a C string.

I deliberately left your program fundamentally unchanged but
readable (and compileable) so you could learn something. Look up
at the start of this message at the two "remember"s I left about
earlier comments for some clues.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943
Aug 19 '06 #11

P: n/a

"CBFalconer" <cb********@yahoo.comwrote in message
news:44***************@yahoo.com...
Michael wrote:
>"CBFalconer" <cb********@yahoo.comwrote in message
>>Michael wrote:
"Michael Mair" <Mi**********@invalid.invalidwrote in message

... snip ...
>
The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.
>
REMEMBER THE ABOVE
... snip ...

Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray
in my function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer
without a cast".

And remember that too.
... snip ...
>>
Thanks for the help, but you don't seem to have changed anything
about the way the array is passed or handled, which is where my
problem is. The array+i still indexes through the first element,
rather than through the array of strings.
I know this is to do with the way I am passing the array, but I
cant figure out what concept I have misunderstood.

const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
so
stringArray[0][0] = 'o'
stringArray[0][1] = 'n'
stringArray[0][2] = 'e'
correct?

so
stringArray[0] = 'one'
correct?

No. stringArray[0] is a pointer to the char array "one\0", which
in turn is a C string.
This is how I understood it. But when I try to step through the array I find
I am stepping through the first element, so have something wrong but I
cannot find what.
I deliberately left your program fundamentally unchanged but
readable (and compileable) so you could learn something. Look up
at the start of this message at the two "remember"s I left about
earlier comments for some clues.
These are clues I already had.
I have been struggling with this for some time and only posted here when I
found I was going in circles.
>
--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943



Aug 19 '06 #12

P: n/a
goose wrote:
CBFalconer wrote:

<snipped>
>You are still using some nominally illegal variable names, i.e.
"stri....". These, among others, are reserved for the
implementation and can nip you in the butt.

AFAIK, "str..." is reserved for function names. Variable
names starting with "str..." are safe.
Extern declarations and definitions of variables of which the names start
with str (followed by a lowercase letter) are not safe, and when <string.h>
is included neither are static declarations and definitions with file
scope. However, it is true that non-file scope variable names can safely
start with str.
Aug 19 '06 #13

P: n/a
Michael schrieb:
"Michael Mair" <Mi**********@invalid.invalidwrote in message
news:4k************@individual.net...
>>Michael schrieb:
>>>I am trying to pass a function an array of strings, but I am having
trouble getting the indexing to index the strings rather than the
individual characters of one of the strings.
I have declared an array as:

char *stringArray[] = {"one","two","three","a"};

When I pass the array using:
CompareStringArray(*stringArray, 3, min); /*I know I have a magic
number here*/

Passing *stringArray is equivalent to passing stringArray[0]
which is the start address of a string containing "one".
>>>Then try to access the elements with
func(array+i, array+result); /* func(char *,
char *) */
the array+i is indexing through the first string, rather than through the
array of strings.

If you posted actual code, then I would not have to guess whether
func is supposed to be CompareStringArray() even though the number
of parameters changed.

The correct prototype for CompareStringArray() has
"char *StringArray[]" or "char **StringArray" as first parameter.

Ok, following is what I have written.

When I originally wrote this I had **stringArray, not *stringArray in my
function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer without a
cast".
I know I have some magic numbers and stuff, I'm really just trying to sort
out the array stuff though.
missing includes
int main(){
char *stringArray[] = {"one","two","three","four","five"};
int smallest;
int largest;

smallest = CompareStringArray(*stringArray, 4, min);
largest = CompareStringArray(*stringArray, 4, max);
pass string array.
>
if(smallest -1){
printf("\nsmallest is %s at position
%d",stringArray[smallest], smallest);
Note: Not the smallest, but one of the smallest.
Another thing: The last character you output to a text
stream should be a '\n', if you want to be sure that your
output "arrives".
}else {
printf("\nempty array");
}
if(largest -1){
printf("\nlargest is %s at position
%d",stringArray[largest], largest);
}else {
printf("\nempty array");
}

fgetc(stdin);
return 0;
}

int max(char *string1, char *string2){
int result = FALSE;

if(strlen(string1) strlen(string2)){
result = TRUE;
}

return result;
}

int min(char *string1, char *string2){
int result = FALSE;

if(strlen(string1) < strlen(string2)){
result = TRUE;
}

return result;
}

int CompareStringArray(char *array, int size, int (*func)(char*, char*)){
char **array
int i;
int result;

if(!strlen(array)){
size 0
result = 0; /*arbitrary starting point
for result*/
for(i = 0; i < size; i++){
if(func(array+i, array+result)){ /*check if current is longer
than longest found yet*/
func(array[i], array[result])
result = i;
}
}
} else {
result = -1; /*zero length array*/
}
return result;
}
I added "const" where appropriate and shortened min() and max():

#include <stdio.h>
#include <string.h>

int CompareStringArray (const char **array,
int size,
int (*func)(const char*, const char*));
int min (const char *string1, const char *string2);
int max (const char *string1, const char *string2);

int main (void)
{
const char *stringArray[] = {"one","two","three","four","five"};
int smallest;
int largest;

smallest = CompareStringArray(stringArray, 4, min);
largest = CompareStringArray(stringArray, 4, max);

if (smallest -1) {
printf("\nOne of the smallest is %s at position %d\n",
stringArray[smallest],
smallest);
}
else {
printf("\nempty array\n");
}
if (largest -1) {
printf("\nOne of the largest is %s at position %d\n",
stringArray[largest], largest);
}
else {
printf("\nempty array\n");
}

getchar();
return 0;
}

int max (const char *string1, const char *string2)
{
return strlen(string1) strlen(string2);
}

int min (const char *string1, const char *string2)
{
return strlen(string1) < strlen(string2);
}

int CompareStringArray (const char **array,
int size,
int (*func)(const char*, const char*))
{
int i;
int result;

if (size <= 0) {
result = -1;
}
else {
result = 0; /*arbitrary starting point for result*/
for (i = 0; i < size; i++) {
if ((*func)(array[i], array[result])) {
/*check if current is longer than longest found yet*/
result = i;
}
}
}

return result;
}
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Aug 19 '06 #14

P: n/a
Michael wrote:
"CBFalconer" <cb********@yahoo.comwrote in message
>Michael wrote:
>>"CBFalconer" <cb********@yahoo.comwrote in message
Michael wrote:
"Michael Mair" <Mi**********@invalid.invalidwrote in message
>
... snip ...
>>
>The correct prototype for CompareStringArray() has
>"char *StringArray[]" or "char **StringArray" as first parameter.
>>
REMEMBER THE ABOVE
... snip ...
>
Ok, following is what I have written.
>
When I originally wrote this I had **stringArray, not *stringArray
in my function call, but the compiler complained:
"passing arg 1 of CompareStringArray makes pointer from integer
without a cast".

And remember that too.
... snip ...
>>>
Thanks for the help, but you don't seem to have changed anything
about the way the array is passed or handled, which is where my
problem is. The array+i still indexes through the first element,
rather than through the array of strings.
I know this is to do with the way I am passing the array, but I
cant figure out what concept I have misunderstood.

const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
so
stringArray[0][0] = 'o'
stringArray[0][1] = 'n'
stringArray[0][2] = 'e'
correct?

so
stringArray[0] = 'one'
correct?

No. stringArray[0] is a pointer to the char array "one\0", which
in turn is a C string.

This is how I understood it. But when I try to step through the array I find
I am stepping through the first element, so have something wrong but I
cannot find what.
>I deliberately left your program fundamentally unchanged but
readable (and compileable) so you could learn something. Look up
at the start of this message at the two "remember"s I left about
earlier comments for some clues.

These are clues I already had.
I have been struggling with this for some time and only posted here when I
found I was going in circles.
You chose the wrong way to fix those initial complaints. Start by
passing the right parameter to CompareStringArray.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943

Aug 19 '06 #15

P: n/a

"Michael" <mi*********@yahoo.comwrote in message
news:44*********************@per-qv1-newsreader-01.iinet.net.au...
>
Thanks for the help, but you don't seem to have changed anything about the
way the array is passed or handled, which is where my problem is.
The array+i still indexes through the first element, rather than through
the
array of strings.
I know this is to do with the way I am passing the array, but I cant
figure
out what concept I have misunderstood.

const char *stringArray[] =
{ "one", "two", "three", "four", "five" };
so
stringArray[0][0] = 'o'
stringArray[0][1] = 'n'
stringArray[0][2] = 'e'
correct?
Yes.
so
stringArray[0] = 'one'
correct?
Yes.
so
*stringArray = 'one'
correct?
Yes.
What you "misunderstood" was how to declare 'array'. This isn't your fault
but a problem with how standard literature describes arrays in C.

You have:
int CompareStringArray(char *array,

When you need:
int CompareStringArray(char **array,

The reason is that C doesn't actually have arrays. C only has pointers and
values. Occasionally, you'll hear about arrays being "second class
citizens" in C. What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays. So, in a declaration: "char
mstr[10]", mstr or mstr[] is thought of as an array. But, [] is actually a
subscript operator which functions on pointers only. Therefore, mstr is a
pointer, not an array. Specifically, mstr is a pointer to preallocated
storage storage of 10 char's. By definition, a[b] is the same as
*((a)+(b)), where a is the pointer. What this means is that "char
array[][]" or "char *array[]" is the same as "char **array".
Here's a sample program based on your post. You'll see your array accessed
using both forms: a[b] and *((a)+(b)).

#include <stdio.h>
#include <stdlib.h>

void pvi(char **mstr)
{
printf("0: %s\n",mstr[0]);
printf("1: %s\n",mstr[1]);
printf("2: %s\n",mstr[2]);
printf("3: %s\n",*(mstr));
printf("4: %s\n",*(mstr+1));
printf("5: %s\n",*(mstr+2));
}

int main(void)
{
char *stringArray[] =
{ "one", "two", "three", "four", "five" };

printf("%s\n",&stringArray[0][0]);
printf("%s\n",&stringArray[0][1]);
printf("%s\n",&stringArray[0][2]);
printf("%s\n",stringArray[0]);
printf("%s\n",stringArray[1]);
printf("%s\n",stringArray[2]);
printf("%s\n",*stringArray);
printf("%s\n",*(stringArray+1));
printf("%s\n",*(stringArray+2));

pvi(stringArray);

return(0);
}
Rod Pemberton
Aug 19 '06 #16

P: n/a
Rod Pemberton wrote:
The reason is that C doesn't actually have arrays.
C only has pointers and values.
Occasionally, you'll hear about arrays being "second class
citizens" in C.
What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays.
That's a pile of crap.
The "second class citizen" status of arrays
has to do with expressions of array type being automaticaly
converted to expressions of pointer type in most circumstances,
which among other things, prevents expressions of array type
from being left operands of the assignment operator.

--
pete
Aug 19 '06 #17

P: n/a

"pete" <pf*****@mindspring.comwrote in message
news:44***********@mindspring.com...
Rod Pemberton wrote:
The reason is that C doesn't actually have arrays.
C only has pointers and values.
Occasionally, you'll hear about arrays being "second class
citizens" in C.
What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays.

That's a pile of crap.
The "second class citizen" status of arrays
has to do with expressions of array type being automaticaly
converted to expressions of pointer type in most circumstances,
And why do you think they are being converted to expressions of pointer
type? Reread completely:

RPThe reason is that C doesn't actually have arrays. C only has pointers
and
RPvalues. Occasionally, you'll hear about arrays being "second class
RPcitizens" in C. What that means is arrays are an artificial construct
in C
RPwhich appear to be arrays but aren't arrays. So, in a declaration:
"char
RPmstr[10]", mstr or mstr[] is thought of as an array. But, [] is
actually a
RPsubscript operator which functions on pointers only. Therefore, mstr is
a
RPpointer, not an array. Specifically, mstr is a pointer to preallocated
RPstorage storage of 10 char's. By definition, a[b] is the same as
RP*((a)+(b)), where a is the pointer. What this means is that "char
RParray[][]" or "char *array[]" is the same as "char **array".
which among other things, prevents expressions of array type
from being left operands of the assignment operator.

Rod Pemberton

Aug 19 '06 #18

P: n/a
Rod Pemberton wrote:
"pete" <pf*****@mindspring.comwrote in message
news:44***********@mindspring.com...
>Rod Pemberton wrote:
>>The reason is that C doesn't actually have arrays.
C only has pointers and values.
Occasionally, you'll hear about arrays being "second class
citizens" in C.
What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays.
That's a pile of crap.
The "second class citizen" status of arrays
has to do with expressions of array type being automaticaly
converted to expressions of pointer type in most circumstances,

And why do you think they are being converted to expressions of pointer
type? Reread completely:
Having reread it completely I am even more convinced it is crap than
when I saw pete saying it was crap.
RPThe reason is that C doesn't actually have arrays. C only has pointers
The C standard disagrees with you.
and
RPvalues. Occasionally, you'll hear about arrays being "second class
RPcitizens" in C. What that means is arrays are an artificial construct
in C
RPwhich appear to be arrays but aren't arrays. So, in a declaration:
Wrong.
"char
RPmstr[10]", mstr or mstr[] is thought of as an array.
Because it is except when it is the declaration of a parameter to a
function.
But, [] is
actually a
RPsubscript operator which functions on pointers only.
True. Fortunately the name of an array gets automatically converted to a
pointer in this situation.
Therefore, mstr is
a
RPpointer, not an array.
Wrong. Or you would be able to do:
mstr = 0;
Also check the value of:
sizeof mstr
Check the type of &mstr, this is a pointer to an array, not a pointer to
a pointer, and it is *not* assignment compatible with a pointer to a
pointer.
Specifically, mstr is a pointer to preallocated
RPstorage storage of 10 char's. By definition, a[b] is the same as
RP*((a)+(b)), where a is the pointer.
Also true by definition when a is an array.
What this means is that "char
RParray[][]" or "char *array[]" is the same as "char **array".
Complete and utter rubish. Try compiling a program that passes an array
of arrays to a function expecting a pointer to a pointer without using
casts and watch the diagnostics fly. Or search the group for all the
occasions where people have tried this or tried it the other way around
and it has not worked. Or just read question 6.18 of the FAQ.
>which among other things, prevents expressions of array type
from being left operands of the assignment operator.
I suggest, Rob, that you read the comp.lang.c FAQ, specifically section
6. You obviously don't yet understand arrays and/or pointers in C.
Either that or you are deliberately trying to mislead.
--
Flash Gordon
Still sigless on this computer.
Aug 19 '06 #19

P: n/a
"Rod Pemberton" <do*********@bitfoad.cmmwrites:
[...]
The reason is that C doesn't actually have arrays. C only has pointers and
values. Occasionally, you'll hear about arrays being "second class
citizens" in C. What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays.
Utter nonsense.

C most certainly does have arrays. There are some serious limitations
on what you can do with array values in expressions; specifically, any
expression of array type is implicitly converted to the address of its
first element *unless* it's the operand of a unary "&" or "sizeof"
operator, or it's a string literal in an initializer used to
initialize an array.

In that sense, arrays are considered "second-class" types. But
there's no rigorous definition of what "second-class" means. There
are a number of operations you can perform on, say, integer types that
you can't (directly) perform on array types -- but the same is true,
to a lesser extent, for structure types. Each set of types has a
defined set of operations that can be performed on it.

The indexing operator takes two operands, a pointer value and an
integer value; for it to work, the pointer value must point to the
first element of an array object.

Pointers are not arrays. Arrays are not pointers. Certain features
of the language can make it difficult, but by no means impossible, to
keep the distinction straight. Section 6 of the comp.lang.c FAQ,
<http://www.c-faq.com/>, does an excellent job of clearing up the
confusion. Please read it.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Aug 19 '06 #20

P: n/a

"Flash Gordon" <sp**@flash-gordon.me.ukwrote in message
news:44**************@flash-gordon.me.uk...
Rod Pemberton wrote:
"pete" <pf*****@mindspring.comwrote in message
news:44***********@mindspring.com...
Rod Pemberton wrote:

The reason is that C doesn't actually have arrays.
C only has pointers and values.
Occasionally, you'll hear about arrays being "second class
citizens" in C.
What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays.
That's a pile of crap.
The "second class citizen" status of arrays
has to do with expressions of array type being automaticaly
converted to expressions of pointer type in most circumstances,
And why do you think they are being converted to expressions of pointer
type? Reread completely:

Having reread it completely I am even more convinced it is crap than
when I saw pete saying it was crap.
And, you'd be wrong.
RPThe reason is that C doesn't actually have arrays. C only has
pointers
>
The C standard disagrees with you.
Actually, it agrees with me completely.
and
RPvalues. Occasionally, you'll hear about arrays being "second class
RPcitizens" in C. What that means is arrays are an artificial
construct
in C
RPwhich appear to be arrays but aren't arrays. So, in a declaration:

Wrong.
Correct.
"char
RPmstr[10]", mstr or mstr[] is thought of as an array.

Because it is except when it is the declaration of a parameter to a
function.
No, it's not.
But, [] is
actually a
RPsubscript operator which functions on pointers only.

True. Fortunately the name of an array gets automatically converted to a
pointer in this situation.
Incorrect.
Therefore, mstr is
a
RPpointer, not an array.

Wrong. Or you would be able to do:
mstr = 0;
Correct, because it is a pointer to a const type (remember preallocated
storage?), i.e., the pointer can't be changed.

<snip>

I'm ignoring the rest of the also incorrect drivel.

Rod Pemberton
Aug 20 '06 #21

P: n/a
Rod Pemberton wrote:
"Flash Gordon" <sp**@flash-gordon.me.ukwrote in message
news:44**************@flash-gordon.me.uk...
>Rod Pemberton wrote:
>>"pete" <pf*****@mindspring.comwrote in message
news:44***********@mindspring.com...
Rod Pemberton wrote:

The reason is that C doesn't actually have arrays.
C only has pointers and values.
Occasionally, you'll hear about arrays being "second class
citizens" in C.
What that means is arrays are an artificial construct in C
which appear to be arrays but aren't arrays.
That's a pile of crap.
The "second class citizen" status of arrays
has to do with expressions of array type being automaticaly
converted to expressions of pointer type in most circumstances,
And why do you think they are being converted to expressions of pointer
type? Reread completely:
Having reread it completely I am even more convinced it is crap than
when I saw pete saying it was crap.

And, you'd be wrong.
True. Crap is useful, it can be made in to fertiliser. What you have
posted is worse than useless, it is dangerous because some poor innocent
who does not know any better might believe you. You've obviously still
not read the FAQ.
>>RPThe reason is that C doesn't actually have arrays. C only has
pointers
>The C standard disagrees with you.

Actually, it agrees with me completely.
C&V. Here is a quote from the standard which defines the term "array type".
| An /array type/ describes a contiguously allocated nonempty set of
| objects with a particular member object type, called the /element
| type/.36) Array types are characterized by their element type and by
| the number of elements in the array. An array type is said to be
| derived from its element type, and if its element type is T, the
| array type is sometimes called 'array of T'. The construction of
| an array type from an element type is called 'array type
| derivation'.

Why would it define an array type if arrays don't exist? Can you quote
anything that says they don't?
>>and
RPvalues. Occasionally, you'll hear about arrays being "second class
RPcitizens" in C. What that means is arrays are an artificial
construct
>>in C
RPwhich appear to be arrays but aren't arrays. So, in a declaration:
Wrong.

Correct.
Nope. Unless you can quote something in the standard that says arrays
are not arrays.
>>"char
RPmstr[10]", mstr or mstr[] is thought of as an array.
Because it is except when it is the declaration of a parameter to a
function.

No, it's not.
C&V? I'll give you a clue, there isn't one.
> But, [] is
actually a
RPsubscript operator which functions on pointers only.
True. Fortunately the name of an array gets automatically converted to a
pointer in this situation.

Incorrect.
It's what the C standard says. Are you saying the C standard is wrong?
To be precise the standard says:
| Except when it is the operand of the sizeof operator or the unary &
| operator, or is a string literal used to initialize an array, an
| expression that has type 'array of type' is converted to an
| expression with type 'pointer to type' that points to the initial
| element of the array object and is not an lvalue. If the array object
| has register storage class, the behavior is undefined.

This seems to agree with what I said about when the subscript operator
is used.
> Therefore, mstr is
a
RPpointer, not an array.
Wrong. Or you would be able to do:
mstr = 0;

Correct, because it is a pointer to a const type (remember preallocated
storage?), i.e., the pointer can't be changed.
This is explicitly addressed in section 6 of the FAQ and you've
obviously failed to read it.
<snip>

I'm ignoring the rest of the also incorrect drivel.
So you are going to ignore all the bits in the C FAQ that point out your
error, and the part where I pointed out that code relying on what you
claim will fail to compile and if forced through with a cast does not work.

Here is a nice simple example where a compiler is *required* to produce
a diagnostic *because* arrays are not the same thing as pointers.

#include <stdlib.h>

int main(void)
{
int a[5];
int *p;
if (&a == &p)
return EXIT_FAILURE;
else
return 0;
}

You can add in const in as many places as you want and the compiler will
continue to complain because it is *required* to. Of course, it is not
required to fail to compile, only to produce a diagnostic.

This is all covered in section 6 of the comp.lang.c FAQ, so here is a
link directly to it since you could not be bothered to read the
questions without a link. I expect you read them this time as well, but
any newbie following this thread will have the chance to read it and see
that you are wrong. http://c-faq.com/aryptr/index.html
--
Flash Gordon
Still sigless on this computer.
Aug 20 '06 #22

P: n/a
On Sat, 19 Aug 2006 08:07:02 +0200, Harald van D?k <tr*****@gmail.com>
wrote:
goose wrote:
CBFalconer wrote:

<snipped>
You are still using some nominally illegal variable names, i.e.
"stri....". These, among others, are reserved for the
implementation and can nip you in the butt.
AFAIK, "str..." is reserved for function names. Variable
names starting with "str..." are safe.

Extern declarations and definitions of variables of which the names start
with str (followed by a lowercase letter) are not safe, and when <string.h>
Right. Or more precisely, declarations of the names for variables or
functions with external linkage. 'External declaration' is used in the
standard to mean at file scope, even with internal linkage; conversely
a declaration in block scope with external linkage (i.e. the 'extern'
keyword) of a library name is unsafe.
is included neither are static declarations and definitions with file
scope. However, it is true that non-file scope variable names can safely
start with str.
But not this. All library function (and variable) names plus the
extension ranges like str[a-z]* are declared (at file scope) _and
optionally #define'd as macros_ if the relevant header is #include'd.
This reservation as a macro name essentially prohibits any other use
unless you #undef it. See the fifth list item in 7.1.3, and 7.1.4p1.

- David.Thompson1 at worldnet.att.net
Sep 4 '06 #23

P: n/a
Dave Thompson wrote:
On Sat, 19 Aug 2006 08:07:02 +0200, Harald van D?k <tr*****@gmail.com>
wrote:
goose wrote:
CBFalconer wrote:
>
<snipped>
>
>You are still using some nominally illegal variable names, i.e.
>"stri....". These, among others, are reserved for the
>implementation and can nip you in the butt.
>
AFAIK, "str..." is reserved for function names. Variable
names starting with "str..." are safe.
Extern declarations and definitions of variables of which the names start
with str (followed by a lowercase letter) are not safe, and when <string.h>

Right. Or more precisely, declarations of the names for variables or
functions with external linkage. 'External declaration' is used in the
standard to mean at file scope, even with internal linkage; conversely
a declaration in block scope with external linkage (i.e. the 'extern'
keyword) of a library name is unsafe.
Technically, I did say "extern declarations", not "external
declarations" :) You're right though, thanks.
is included neither are static declarations and definitions with file
scope. However, it is true that non-file scope variable names can safely
start with str.

But not this. All library function (and variable) names plus the
extension ranges like str[a-z]* are declared (at file scope) _and
optionally #define'd as macros_ if the relevant header is #include'd.
This reservation as a macro name essentially prohibits any other use
unless you #undef it. See the fifth list item in 7.1.3, and 7.1.4p1.
No, str[a-z]* may only be defined as function-like macros, not
object-like macros. See 7.1.4p1 again, but take into account that
7.26.11 by itself only permits str[a-z]* function declarations.

Sep 4 '06 #24

P: n/a
On 4 Sep 2006 01:18:55 -0700, "Harald van D?k" <tr*****@gmail.com>
wrote:
Dave Thompson wrote:
On Sat, 19 Aug 2006 08:07:02 +0200, Harald van D?k <tr*****@gmail.com>
wrote:
<about str*>
Extern declarations and definitions of variables of which the names start
with str (followed by a lowercase letter) are not safe, and when <string.h>
Right. Or more precisely, declarations of the names for variables or
functions with external linkage. 'External declaration' <snip>

Technically, I did say "extern declarations", not "external
declarations" :) You're right though, thanks.
Glark! So you did. I somehow read that as 'External', which people too
often use somewhat loosely, but you did not. Sorry.
is included neither are static declarations and definitions with file
scope. However, it is true that non-file scope variable names can safely
start with str.
But not this. All library function (and variable) names plus the
extension ranges like str[a-z]* are declared (at file scope) _and
optionally #define'd as macros_ if the relevant header is #include'd.
This reservation as a macro name essentially prohibits any other use
unless you #undef it. See the fifth list item in 7.1.3, and 7.1.4p1.

No, str[a-z]* may only be defined as function-like macros, not
object-like macros. See 7.1.4p1 again, but take into account that
7.26.11 by itself only permits str[a-z]* function declarations.
Well, yes, but. IME it's awful easy to somewhere, accidentally, end up
with an object(like) name adjacent to a parentheses, and then you get
very confusing problems; it's easier to just err a bit on the side of
safety. (This is similar to my position on names beginning with
underscore.) But I'll concede you can use it carefully as a variable,
and I shouldn't overstate the case when we're being exact.

- David.Thompson1 at worldnet.att.net
Sep 10 '06 #25

This discussion thread is closed

Replies have been disabled for this discussion.