Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

understanding char arrays...

Status
Not open for further replies.

hansdampf3

Programmer
Oct 31, 2003
4
DE
Hi erveryone!

I'm quite new to C programming and I'm not sure whether the following little programm is correct and why it crashes with a single line uncommented. Heres the prog:

/***************************************/
#include <stdio.h>

int main(int argc, char *argv[])
{
const char *text[3][3] = {
{ &quot;Hello&quot;, &quot;I'm&quot;, &quot;the&quot;},
{&quot;sample&quot;, &quot;char&quot;, &quot;array&quot;},
{ &quot;and&quot;, &quot;I'm&quot;, &quot;mean&quot;}
};

/*text[0][0][0]='r';/* /* This line will crash. Why??? */

printf(&quot;Line 1: %c %c %c \n&quot;, text[0][0][0], text[0][0][1], text[0][0][2]);

/* correct output: H e l */

return 0;
}
/***************************************/

There are a few points I'm not quite sure of.

First of all, the definition of 'const char *[3][3]' ... is this really correct? The prog works as intended this way, but does the needed memory for the const &quot;strings&quot; gets allocated? Or is it as if I would do a

char *p;
sprintf (p, &quot;testext&quot;);

which surely is very wrong.


The next point is the commented line 'text[0][0][0]='r';' which crashes the prog. Why? The following printf doesn't crash and outputs the right chars. This seems very strange to me.

Or maybe one could define the char array in a other way. From my understanding so far I would write:

char[][][] = {{...},{...},{...}};

but this doesn't compile. Error is &quot;storage size of text unknown&quot;, but as I define the strings directly within the initialisation, the compiler should know the exact size. Or am I wrong?

Where's the difference in writing:

char[] = &quot;This works!&quot;;

This compiles and works just fine. But if defining a char array, like in the prog given, it's somehow not possible. I don't understand the difference...

Would be very nice if someone could help me with these issues. Or anyone has a idea how to define a 3-dimensional char array. Surely I could use malloc for allocating the needed memory for the strings, but since they are const this shouldn't be neccessary.

Thanks and many greetz,
Sebastian




 
const char *text[3][3] = {
{ &quot;Hello&quot;, &quot;I'm&quot;, &quot;the&quot;},
{&quot;sample&quot;, &quot;char&quot;, &quot;array&quot;},
{ &quot;and&quot;, &quot;I'm&quot;, &quot;mean&quot;}

you have only [3] array for each of your string, so each string is no more then 2 characters one reserved for \0.
text get allocated in stack memory instead of dynamic memory, so you not simply corrupted dynamicly allocated memory you corrupted stack, after that bihaviuor of your program is undefined, so do not try to understand why it works this way.
To fix change *text[3][3] to *text[3][7] where 7 is lenght of your longest string +1
 
Your problem that you thought that your definition allocate space specificly for you strings, but it counting number of 2 dimensional arrays [3][3] and it 3, so you have array text[3][3][3].
In C you can not allocate array with different lenght of elements, if at least one string is 7 chars, all should be 7. Array is continues space in memory, so it looks like this (\0 is one character):
-0------------------------------------29-------->
&quot;Hello\0 I'm\0 the\0 sample\0char\0 array\0 and\0 I'm\0 mean\0 &quot;

So text[1][1][2] means go to 0 position of array (letter H) and add 1*(3*7) + 1*7 + 2= 29
So you move from H and add 29 character to right and get &quot;a&quot; in char.
 
> /*text[0][0][0]='r';/* /* This line will crash. Why??? */
Because (for your compiler at least), string constants are stored in read-only memory. That is, after the operating system has finished loading your program (and string constants), it marks that area of memory as read-only. Any attempt to write to it will cause a trap to the operating system, and it's goodbye program.

> First of all, the definition of 'const char *[3][3]' ... is this really correct?
Yes, it's correct from the compiler's point of view. From your perspective, if you're looking to change the strings then its wrong.

> but does the needed memory for the const &quot;strings&quot; gets allocated?
Yes, the compiler does it for you.
It's a bit like
Code:
const char *anonymous1 = &quot;Hello&quot;;
const char *anonymous2 = &quot;I'm&quot;;
...
const char *text[3][3] = { { anonymous1, anonymous2...
Except that the anonymous char pointers never really exist outside the compiler - it fills them in automatically for you.

> char[][][] = {{...},{...},{...}};
You can only leave the left-most array empty
So you could do
Code:
const char *text[][3] = { ...

or, if you wanted strings you can modify
Code:
const char *text[][3][7] = { ...
7 being the length + 1 of your longest string, as noted by Lim (but for the wrong reasons)

> Error is &quot;storage size of text unknown&quot;
The compiler needs to know the size of all the minor dimensions up front.

> char array[] = &quot;This works!&quot;;
This creates an array, and initialises it with the given string. Note that this is an array (a single object), not a pointer to a string (which is two objects - the pointer, and the pointed to)

--
 
Thanks for your replys!

It's clearer to me now. The right way for my definition would be

const char *text[][7] = ...

where the 7 is the lenght of my longest string + 1. Right?

Another question: Does the const matter? Would

char *anonymous = &quot;Hello Mr. Bill&quot;

also be correct? Or does the compiler implicitly regard this as const?

Thanks again,
Sebastian
 
I've just ran a few tests and it seems the definition of char *text[][7] isn't the one i want. The [7] doesn't stand for the number of chars in each string, but for the number of strings in each &quot;row&quot;. Therefore I can write

char *text[][3],

but the chars of each string are only represented by the * in this way. Actually it's only an array of char-pointers, but as Salem points out, these pointers never really exist outside the compiler. As I understand this, the pointers get &quot;substituted&quot;, whereas enough space for each string gets allocated. But as Lim said, in C there can't be arrays with different sizes of elements. So this is a bit contradictory...

@Salem:
>or, if you wanted strings you can modify
>const char *text[][3][7] = { ...
>7 being the length + 1 of your longest string, as noted by Lim (but for the wrong reasons)

You meant const char[][3][7], right? Without the *. Then the [7] really stands for the number of chars in each string. But then again, I would say a definition like

char *text[][3] = ...

is wrong, because the space for the strings doesn't get allocated. And it can't get allocated because the length of the elements can't differ. Or maybe I'm bypassing the C array concept with this definition. The compiler simply allocates as much space as needed for each string. I don't know...
 
You have to see the array in dimensions.

char Buffer[5] means an one dimensional array with a maximum of 5 characters so 'abcd\0'. The array has to be closed with a '\0'. It's a null terminated string.

char Buffer[2][5] means a two dimensional array with a maximum of 5 characters per row. There are two rows with five characters each:
row 1: 'abcd\0'
row 2: 'fghi\0'

Take also a look at:

Good luck.
 
I think char *text[][7] should work. 7 is the lenght of char in string, yes not a *text[][3][7] and
*text[][7] and text[][3][7] is the same in your case. the only difference in first case you can cheat compiler and ommit two dimensions.

char *text[][3] = ... in this case space got allocated but for 3 elemnts for each string (2 chars and \0).

Actually I don't like using
char *text[][3] = {}; type of definition, because it create False impression that this is dynamic array and you have to allocate it, but using ={...,...} make it auto allocated in stack and invoke complitly different handling of this array.

So use * only for Real pointers and use [] for auto allocated arrays.

Plus, in real life you should be VERY CAREFUL with all stack arrays, the error with them is most common and the most difficult to find out, since it screw up stack it can screw up your debuger.

About Kocky remark with multi-dimension thinking:
It might be good to understand what is a multi-dim arrays in theory, but it is wrong from compiler point of view. For compiler everything is one dimentional array with specific shifts.
Like a[2][3] is just *((*(a+2))+3) and
a[2] is *(a+2). So from here you can see that a[2] is the same as 2[a] == *(2+a)
 
You got it all wrong Lim, if you have a char* array, then NONE of the array dimensions have anything to do with the lengths of any of the strings contained within the array.

Code:
char *a[2] = { &quot;this is one long string&quot;, &quot;and so is this one&quot; };
See - two strings (as specified by the [2]), and neither of them restricted in length.

Your other comments about arrays suggest that you've got some stuff to learn as well.

> Another question: Does the const matter? Would
> char *anonymous = &quot;Hello Mr. Bill&quot;
> also be correct? Or does the compiler implicitly regard this as const?
Strictly speaking, you should have const in front of your declaration. When C was standardised, one of the changes made was to make &quot;strings&quot; constants (which they are, because you've seen the program crash if you try to change them). However, a lot of code existed already, so generally speaking, compilers don't complain when you do
char *anonymous = &quot;Hello Mr. Bill&quot;
instead of
const char *anonymous = &quot;Hello Mr. Bill&quot;

> You meant const char[][3][7], right? Without the *. Then the [7] really stands for the number of chars in each string.
Yes ( and good catch on the typo :) )
char *text[][3] or
char text[][3][7]


> The compiler simply allocates as much space as needed for each string
For each &quot;string&quot;, the compiler allocates the memory - you don't have to worry about it at all, whether its a simple
char *me = &quot;you&quot;;
or something more complicated like in your original post.

Perhaps this will help

--
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top