simple array question

M

Michael

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
 
M

Michael Mair

Michael said:
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
 
K

Keith Thompson

Michael said:
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/>.
 
C

CBFalconer

Michael said:
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 for some i from 0 to the number available.

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

for (i = 0; i < 3; i++) {
p = arr;
/* 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
 
M

Michael

Michael Mair said:
Michael said:
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

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;
}
 
P

pete

Michael said:
Michael Mair said:
Michael said:
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

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 */
 
C

CBFalconer

Michael said:
.... 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
 
J

Joe Wright

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

Michael

CBFalconer said:
Michael said:
... 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
 
C

CBFalconer

Michael said:
CBFalconer said:
Michael said:
... 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
 
G

goose

CBFalconer wrote:

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,
 
M

Michael

CBFalconer said:
Michael said:
CBFalconer said:
Michael wrote:

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

Harald van =?UTF-8?B?RMSzaw==?=

goose said:
CBFalconer wrote:



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

CBFalconer

Michael said:
CBFalconer said:
Michael said:
Michael wrote:

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

Michael Mair

Michael said:
Michael Mair said:
Michael said:
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, 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, array[result])) {
/*check if current is longer than longest found yet*/
result = i;
}
}
}

return result;
}


Cheers
Michael
 
R

Rod Pemberton

Michael said:
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 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 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
 
P

pete

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

Rod Pemberton

pete said:
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:

RP> The reason is that C doesn't actually have arrays. C only has pointers
and
RP> values. Occasionally, you'll hear about arrays being "second class
RP> citizens" in C. What that means is arrays are an artificial construct
in C
RP> which appear to be arrays but aren't arrays. So, in a declaration:
"char
RP> mstr[10]", mstr or mstr[] is thought of as an array. But, [] is
actually a
RP> subscript operator which functions on pointers only. Therefore, mstr is
a
RP> pointer, not an array. Specifically, mstr is a pointer to preallocated
RP> storage storage of 10 char's. By definition, a is the same as
RP> *((a)+(b)), where a is the pointer. What this means is that "char
RP> array[][]" 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
 
F

Flash Gordon

Rod said:
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.
RP> The reason is that C doesn't actually have arrays. C only has pointers

The C standard disagrees with you.
and
RP> values. Occasionally, you'll hear about arrays being "second class
RP> citizens" in C. What that means is arrays are an artificial construct
in C
RP> which appear to be arrays but aren't arrays. So, in a declaration:
Wrong.

"char
RP> mstr[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
RP> subscript 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
RP> pointer, 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
RP> storage storage of 10 char's. By definition, a 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
RP> array[][]" 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.

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

Keith Thompson

Rod Pemberton said:
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.
 

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,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top