How does this storage of a string in a multi-dimensional int array work

A

Angus

I was wondering how this worked.

#include <stdio.h>

int main(){

int pos = 1;

static const int tbl2[6][4] = {
1000, 1, 10, (int)"abc",
1001, 2, 11, (int)"defg",
1100, 3, 12, (int)"hijkl",
1000, 4, 13, (int)"mnopqr",
1001, 5, 14, (int)"stuvwxyz",
1100, 6, 15, (int)"1234567890"
};

printf("row=%i, col1=%i, col2=%i, col3=%i, col4=%s\n", pos,
tbl2[pos][0], tbl2[pos][1], tbl2[pos][2], tbl2[pos][3]);

return 0;
}

This will print:
row=1, col1=1001, col2=2, col3=11, col4=defg

I was a little surprised it worked.

How are the fourth column items stored? I assume that in the array
the fourth column items are all stored as char pointers and so can be
stored in an int. Because this is a static I assume there is some
global section of memory where these items are stored?

If this array were stored in a program then the executable should grow
by sizeof(char) * total string length?
 
F

Fred

I was wondering how this worked.

#include <stdio.h>

int main(){

   int pos = 1;

   static const int tbl2[6][4] = {
      1000, 1, 10, (int)"abc",
      1001, 2, 11, (int)"defg",
      1100, 3, 12, (int)"hijkl",
      1000, 4, 13, (int)"mnopqr",
      1001, 5, 14, (int)"stuvwxyz",
      1100, 6, 15, (int)"1234567890"
   };

   printf("row=%i, col1=%i, col2=%i, col3=%i, col4=%s\n", pos,
tbl2[pos][0], tbl2[pos][1], tbl2[pos][2], tbl2[pos][3]);

   return 0;

}

This will print:
row=1, col1=1001, col2=2, col3=11, col4=defg

I was a little surprised it worked.

How are the fourth column items stored?  I assume that in the array
the fourth column items are all stored as char pointers and so can be
stored in an int.  

Doesn't work on my computer, where sizeof(char*) != sizeof(int)
 
K

Keith Thompson

Angus said:
I was wondering how this worked.

#include <stdio.h>

int main(){

int pos = 1;

static const int tbl2[6][4] = {
1000, 1, 10, (int)"abc",
1001, 2, 11, (int)"defg",
1100, 3, 12, (int)"hijkl",
1000, 4, 13, (int)"mnopqr",
1001, 5, 14, (int)"stuvwxyz",
1100, 6, 15, (int)"1234567890"
};

printf("row=%i, col1=%i, col2=%i, col3=%i, col4=%s\n", pos,
tbl2[pos][0], tbl2[pos][1], tbl2[pos][2], tbl2[pos][3]);

return 0;
}

This will print:
row=1, col1=1001, col2=2, col3=11, col4=defg

I was a little surprised it worked.

How are the fourth column items stored? I assume that in the array
the fourth column items are all stored as char pointers and so can be
stored in an int. Because this is a static I assume there is some
global section of memory where these items are stored?

The entire array is stored in some region of memory that persists
as long as the program is running, because it has what the language
standard calls "static storage duration". But you could drop the
"static" (which would cause it to be in storage that goes away when
the enclosing block terminates) and the "const", and it probably
wouldn't change the results.
If this array were stored in a program then the executable should grow
by sizeof(char) * total string length?

The fact that the int elements are part of an array is irrelevent.
Here's a simpler program that illustrates the same thing:

#include <stdio.h>

int main(void) {
const int s = (int)"Don't do this"; /* line 4 */
printf("%s\n", s); /* line 5 */
return 0;
}

When a string literal, or any array expression, is evaluated, it's
implicitly converted to a pointer to its first element (usually; see
below [*]).

On line 4, a pointer to the 'D' in the string is converted from char*
to int. The result of such a conversion is implementation-defined.
If pointers are bigger than ints, it's likely to lose information.
Even if they aren't, the result is likely to be meaningful, but it
doesn't have to be. (My debugger tells me that, on my system, the
value happens to be 134513888, which means that the string starts at
memory address 0x080484e0. Your results are very likely to differ.)

Typically a pointer-to-integer conversion will just copy the bits of the
representation, but other behaviors are permitted; the implementation
just has to document it.

On line 5, we pass an int value to printf, with a "%s" format, which
expects a char* argument. This isn't just implementation-defined, it's
undefined behavior; passing anything other than a char* means you're
lying to printf, and it can do anything it likes. *If* int arguments
and char* arguments happen to be passed to variadic functions in the
same way (which is commonly true), then the bits making up the
representation of s are likely to be interpreted by printf *as if* they
were the bits making up the representation of a char* object. Note that
this isn't a value conversion; the code is interpreting the raw memory
containing the value of s as if it were a pointer object.

Now *if* the pointer-to-integer conversion on line 4 just copied the
bits, then this reinterpretation of the int object as if it were a char*
is likely to behave as if it really were a char* object pointing to the
first character of the string literal "Don't do this".

Note that I wrote "likely", not "certain". One of the many things that
could go wrong is that char* might have stricter alignment requrements
than int. Suppose both types are 4 bytes, char* requires 4-byte
alignment, int only requires 2-byte alignment, and s happens to be
allocated at an address that's not a multiple of 4 bytes. Then trying
to read the contents of s as if it were a char*, even though all the
bits are correct, could behave in arbitrarily bad ways, from crashing
the program, to quietly ignoring the low-order bits, to whatever else
you can think of.

The bottom line is that the program's behavior is undefined. If
anything goes wrong, it's the fault of the program, not of the
implementation.

In this particular case, on my implementation and on yours, the
undefined behavior gave us the worst result possible: it appeared
to behave "correctly" -- which just makes it that much harder to
track down the problem.

[*] I wrote above that an array expression, whene evaluated,
is implicitly converted to a pointer to its first element.
This conversion doesn't happen of the expression is the operand of
a unary "&" or "sizeof" operator, or if it's a string literal in
an initializer used to initialize an array object. For example,
``sizeof "hello"'' yields 6 (the size of the array object, including
the terminating '\0'), not sizeof (char*), which is what it would
yield if the conversion were done.
 
A

Angus

I was wondering how this worked.
#include <stdio.h>
int main(){
   int pos = 1;
   static const int tbl2[6][4] = {
      1000, 1, 10, (int)"abc",
      1001, 2, 11, (int)"defg",
      1100, 3, 12, (int)"hijkl",
      1000, 4, 13, (int)"mnopqr",
      1001, 5, 14, (int)"stuvwxyz",
      1100, 6, 15, (int)"1234567890"
   };
   printf("row=%i, col1=%i, col2=%i, col3=%i, col4=%s\n",pos,
tbl2[pos][0], tbl2[pos][1], tbl2[pos][2], tbl2[pos][3]);
   return 0;

This will print:
row=1, col1=1001, col2=2, col3=11, col4=defg
I was a little surprised it worked.
How are the fourth column items stored?  I assume that in the array
the fourth column items are all stored as char pointers and so can be
stored in an int.  

Doesn't work on my computer, where sizeof(char*) != sizeof(int)






Because this is a static I assume there is some
global section of memory where these items are stored?
If this array were stored in a program then the executable should grow
by sizeof(char) * total string length?

Out of interest, what is the platform?
 
S

Spiros Bousbouras

I was wondering how this worked.

By accident.
#include <stdio.h>

int main(){

int pos = 1;

static const int tbl2[6][4] = {
1000, 1, 10, (int)"abc",
1001, 2, 11, (int)"defg",
1100, 3, 12, (int)"hijkl",
1000, 4, 13, (int)"mnopqr",
1001, 5, 14, (int)"stuvwxyz",
1100, 6, 15, (int)"1234567890"
};

printf("row=%i, col1=%i, col2=%i, col3=%i, col4=%s\n", pos,
tbl2[pos][0], tbl2[pos][1], tbl2[pos][2], tbl2[pos][3]);

return 0;
}

This will print:
row=1, col1=1001, col2=2, col3=11, col4=defg

Perhaps it will , perhaps it will print something else , perhaps it
will just crash.
I was a little surprised it worked.

C programming is full of surprises , both pleasant and unpleasant ones.
How are the fourth column items stored? I assume that in the array
the fourth column items are all stored as char pointers and so can be
stored in an int.

There is no guarantee that a char* can be stored in an int .For your
code to work as you think it will it is necessary that a char* can be
stored in an int |and| that when converted back to char* it will compare
equal to the original pointer. The second part is necessary for the
printf(...%s...) to work. There's no guarantee that the second part
will work either.
Because this is a static I assume there is some
global section of memory where these items are stored?

What is a "global section of memory" ?
If this array were stored in a program then the executable should grow
by sizeof(char) * total string length?

It is always the case that sizeof(char) == 1 .The space to store all
the stuff in the array and all the stuff in the initialiser would have
to be at least sizeof(int) * 6 * 4 plus the total length of the strings.
How much larger the executable will become or indeed if there will be
an executable depends on the translator which might be an interpreter
in which case it won't produce an executable.
 
K

Keith Thompson

Spiros Bousbouras said:
There is no guarantee that a char* can be stored in an int .For your
code to work as you think it will it is necessary that a char* can be
stored in an int |and| that when converted back to char* it will compare
equal to the original pointer. The second part is necessary for the
printf(...%s...) to work. There's no guarantee that the second part
will work either.
[...]

There is no conversion back to char*. Given certain assumptions, printf
will interpret the contents of the int object as if it were a char*
object. This may well have the same effect as a value conversion, but
it might not.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top