Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Oct 14th, 2005, 9:15 PM   #1
aznluvsmc
Hobbyist Programmer
 
Join Date: Aug 2005
Posts: 137
Rep Power: 4 aznluvsmc is on a distinguished road
Question about multidimensional arrays of strings

Hi,

I'd just like to know if the following two declarations to create an array of strings are equivalent to each other.

int main(void)
{
     char *strings1[5];
     char strings2[5][21];
}

From my understanding, strings1 is an array of 5 pointers-to-char and strings2 is an array of 5 arrays of 21 char elements. In both cases, I see that they can both hold strings but strings2 can only hold a string with a max size of 20 characters whereas strings1 can hold variable length strings using dynamic memory allocation. I guess the better question is, can strings2 be equivalently expressed as strings1 and vice-versa?

Sorry if this sounds like such a noob question but my understanding on creating arrays of strings is kind of fuzzy.
aznluvsmc is offline   Reply With Quote
Old Oct 14th, 2005, 9:19 PM   #2
Narue
Professional Programmer
 
Narue's Avatar
 
Join Date: Sep 2005
Posts: 419
Rep Power: 4 Narue is on a distinguished road
>I guess the better question is, can strings2 be equivalently expressed as strings1 and vice-versa?
This is a subtle area of the language, but yes, strings2 can be equivalently expressed as strings1 and vice-versa.
__________________
Even if the voices aren't real, they have some pretty good ideas.
Narue is offline   Reply With Quote
Old Oct 14th, 2005, 9:53 PM   #3
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,254
Rep Power: 5 grumpy will become famous soon enough
This is another form of the old question about equivalence of pointers and arrays.

Although the language treats pointers and arrays as equivalent in some contexts (i.e. one can be used where the other one can) they are not exactly the same thing.

In the example;

char *strings1[5]; declares an array of five pointers. Those pointers are uninitialised, and it is necessary to make them point at something valid before they can be used.

char strings2[5][21]; is a two dimensional array of characters. strings2[i] (for i in the range [0, 4]) is a one-dimensional array of 21 characters. strings2[i], when used in an expression, is also a char * pointer.

The following expands on the example, with a few possible usages and comments about what happens;
#include <string.h>

int main()
{
     int i;

     char *strings1[5];
     char strings2[5][21];

     strcpy(strings1[3], "Hello");    /*   Undefined behaviour:  strings1[3] not initialised to point at anything */
     strcpy(strings2[3], "Hello");   /*   OK.  string2[3] is treated as a pointer   */

     for (i = 0; i < 5; ++i)
         strings1[i] = strings2[i];

     strcpy(strings1[3], "Hello");    /*   Now OK; strings1[3] equivalent to strings2[3] */
     strcpy(strings2[3], "Hello");   /*    Still OK.  Does the same as previous line   */

     for (i = 0; i < 5; ++i)
     {
         strings1[i] = (char *)0;    /* OK;  setting strings1[i] to be NULL pointer */
         strings2[i] = (char *)0;    /* Compile error.  string2[i] is not really a pointer */
     }
       
}
grumpy is offline   Reply With Quote
Old Oct 14th, 2005, 10:33 PM   #4
aznluvsmc
Hobbyist Programmer
 
Join Date: Aug 2005
Posts: 137
Rep Power: 4 aznluvsmc is on a distinguished road
If both are essentially equivalent. Isn't there still a limitation on strings2[5][21] where each one dimensional array should only be 20 characters long since the max element is 21? However *strings1[5] imposes no limitation on the length of the string since it's a point to another memory location.

Also is the following code correct?

[code]
int main(void)
{
char *strings1[5];
char strings2[5][21];

strings1[0] = "Hello"; //this will assign the beginning address of the Hello string to the first element?

strings2[0] = "Hello"; //invalid because strings2[0] is an array?
}
aznluvsmc is offline   Reply With Quote
Old Oct 15th, 2005, 2:17 AM   #5
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,254
Rep Power: 5 grumpy will become famous soon enough
Quote:
Originally Posted by aznluvsmc
If both are essentially equivalent.
They are only equivalent in some contexts.

To understand what I mean with the underlined bit, consider the "strcpy(strings2[3], "Hello");" from my previous post.

The line "strcpy(strings2[3], "Hello");" actually passes two pointers to strcpy. Now, what does strcpy() do?

Two (notional) implementations are;
char *strcpy(char *x, const char *y)
{
    char *temp = x;
    while (*y)
    {
        *x = *y;
        ++x;
        ++y;
    }
    return temp;
}
or
char *strcpy(char *x, const char *y)
{
    size_t index = 0;
    while (y[index])
    {
         x[index] = y[index];
         ++index;
    }
    return x;
}
Apart from any errors I've inserted in the process of typing, these two versions given the same end result. However, the first version takes the pointers given, manipulates the characters being pointed to, and increments the pointers. In this way, the first version implicitly assumes that the pointers correspond to arrays. The second version explicitly treats the arguments as if they are arrays.

A hybrid version (which is also equivalent) is;
char *strcpy(char *x, const char *y)
{
    size_t index = 0;
    while (*(y + index))
    {
         *(x + index) = (y + index);
         ++index;
    }
    return x;
}
Quote:
Originally Posted by aznluvsmc
Isn't there still a limitation on strings2[5][21] where each one dimensional array should only be 20 characters long since the max element is 21?
That is a side effect of declaring strings2 as a two-dimensional array as you have. The basic principle is that an n-dimensional array is an array of (n-1)-dimensional arrays. The so-called equivalence of arrays and pointers means that the name of an array can be used in some contexts where a pointer is expected, and that pointer notation can be used to access elements of an array. An equivalent (if backward) statement of this is that a pointer can often be treated as if it is an array.

strings2[i] is, according to your declaration, an array of char. "Hello" is also a (const) array of char. strcpy() accepts a pointer to char as first argument, and a const pointer to char as second argument. When you use strings2[i] in code after the declaration (eg in my previous example, a call to strcpy) those arrays may be implicitly manipulated as if they are pointers.

Quote:
Originally Posted by aznluvsmc
However *strings1[5] imposes no limitation on the length of the string since it's a point to another memory location.
The declaration of string1 does not even require that the elements of string1 are strings at all. A pointer is allowed to point at anything. There is nothing preventing strings1[i] from pointing at a single char (which may not even be part of a string), and nothing preventing it pointing at the first element of a string of arbitrary size.

Quote:
Originally Posted by aznluvsmc
Also is the following code correct?
int main(void)
{
     char *strings1[5];
     char strings2[5][21];

    strings1[0] = "Hello";  //this will assign the beginning address of the Hello string to the first element?

    strings2[0] = "Hello"; //invalid because strings2[0] is an array?
}
That depends on what you mean by "correct". The first assignment is valid but also dubious as "Hello" is actually a const string (which is why some compilers will issue a warning in this case). The second assignment will not compile, as the compiler has enough information to know strings2[0] is an array, and arrays cannot be reassigned.

Things get more interesting if you subsequently try to manipulate strings1[0], as "Hello" is implicitly const (i.e. it should not be modified).

As an exercise, try to explain why this code yields undefined behaviour;
int main()
{
     char *strings1[5];

    strings1[0] = "Hello";

    strcpy(strings1, "Junk");
}
grumpy is offline   Reply With Quote
Old Oct 15th, 2005, 2:42 AM   #6
Navid
Hobbyist Programmer
 
Navid's Avatar
 
Join Date: Feb 2005
Location: Canada
Posts: 187
Rep Power: 4 Navid is on a distinguished road
Send a message via MSN to Navid
char array[21];

Just to point out that if you declare an array like above, the array has 21 elements, not 20. From 0-20, including the 0 are all elements. Sorry if Grumpy already mentioned that.
Navid is offline   Reply With Quote
Old Oct 15th, 2005, 8:38 AM   #7
aznluvsmc
Hobbyist Programmer
 
Join Date: Aug 2005
Posts: 137
Rep Power: 4 aznluvsmc is on a distinguished road
Quote:
Originally Posted by Navid
char array[21];

Just to point out that if you declare an array like above, the array has 21 elements, not 20. From 0-20, including the 0 are all elements. Sorry if Grumpy already mentioned that.
You're right, it has 21 elements but only 20 can be used to store the string characters in this example which was what I was referring to.

Thanks for your time Grumpy. In your last example, strings[0] stores a pointer to "Hello" first. But I guess it's also a constant string (still not sure what the rules governing this are) which means strings[0] is not modifiable after that point?
aznluvsmc is offline   Reply With Quote
Old Oct 15th, 2005, 9:33 PM   #8
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,254
Rep Power: 5 grumpy will become famous soon enough
Quote:
Originally Posted by aznluvsmc
In your last example, strings[0] stores a pointer to "Hello" first. But I guess it's also a constant string (still not sure what the rules governing this are) which means strings[0] is not modifiable after that point?
Not quite. strings1[0] can be modified (in the sense that it can be reassigned to point at something else). The problem with assigning it to a string literal is that the string literal cannot be modified without invoking undefined behaviour.

So;
#include <stdlib.h>    /* so we can use malloc() */

int main()
{
    char *strings1[5];
    strings1[0] = "Hello";
    strings1[0][0] = 'A';      /* undefined behaviour as string literal is const */
    
    strings1[0] = malloc(1); /* OK: strings1[0] is a pointer, not an array */ 
    strings1[0][0] = 'A';     /* OK, if malloc() call succeeded */
    strings1[0][1] = 'B';     /*  undefined behaviour:falling off end of array */ 
}
grumpy is offline   Reply With Quote
Old Oct 15th, 2005, 11:20 PM   #9
aznluvsmc
Hobbyist Programmer
 
Join Date: Aug 2005
Posts: 137
Rep Power: 4 aznluvsmc is on a distinguished road
Alright, thanks for your help guys! Greatly appreciated.
aznluvsmc is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 3:36 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC