Friday 25 July 2014

char* is not a synonym for char[]

... was the subject of a mail I wrote to friend, who replied:

... no, it's not a synonym. One of the ways in which they differ is in
declarators, as you see.

> int main(int argc, char *argv[])
>
> {
>         char ok[] = "abcd";
This means 'ok[] is an array, as large as necessary, in writeable
storage, containing the string "abcd\0"'.

>         char *broken = "abcd";

This means 'broken is a pointer to a character, pointing to the literal
string, in unmodified program text, "abcd". (Technically, this should be
'const char *': in C++, this is mandatory.)

Another difference: sizeof(ok) is the size of the array, in bytes;
sizeof(broken) is the size of a pointer to char on this platform.

In *parameter lists*, char *foo and char foo[] are synonyms, because
arrays decay to pointers *when passed to functions*. Otherwise, they are
not. (In this case sizeof() both will give the same answer.)

>         /* this is ok */
>
>         ok[0]= 'Z';
Yep. That's modifiable storage.

>         printf("ok = %s\n", ok);
>
>         /* this segfaults */
>
>         broken[0] = 'Z';
Can't modify program text, this is not FORTRAN where you could pass in
the number 3 to a function and then modify it to change the value of 3
throughout the universe, uh, I mean your program. :P

> TIL C is short for 'Confusion'.
The general rule is that in declarators, you're declaring exactly what
it looks like: foo *bar is a *pointer*, not a buffer of anything, so
assigning to it will assign to *some other buffer somewhere else*. foo[]
bar is a convenience notation for making an array on the stack, as long
as necessary, and then initializing it as with memcpy() with an
appropriate size. (Not strcpy() -- you can do this:

char containsnulls[] = "foo\0bar"

which will make an eight-byte array containing "foo\0bar\0". strcpy()
would only fill in the first four bytes of that.)

This general distinction is crucial to get the hang of, because very
often you want to declare things *not* on the stack -- that outlive
their containing function -- and then you genrally have to declare them
as a foo * and allocate and free them by hand. So remembering where your
things live (that char foo[] lives on the stack, while char foo * merely
puts the pointer on the stack while the data lives elsewhere) is
essential.

Friday 11 July 2014

Shlemiel, the painter

A friend sent me this delightful joke which also doubles up as a puzzle, after I complained that the more I study, the longer my to-do list gets.

 (Go on, solve it, you know you want to.)

Personally, I think this was the best comment:

"You do realize, we're trying to sum up Stupidity as a Mathematical Equation."

But I also like the big collection of possible approaches --- those solutions have everything!

My solution is here, hidden as blue text on blue background:

Shlemiel can walk M meters per day, and his effort can be modelled as an Arithmetic series S_n  with the points S_x, S_y and S_z, therein, so we're looking for M = S_x,  2M = S_y and 3M = S_z and the values of x, y and z which give us the total distance reached on each day.

Rearranging S_n = n/2 (2p + d(n+1)) we get 2 S_n = dn^2 + dn +2pn = [(2S_n - 2pn) / d ] - n = n^2. 

(where p is the initial length and d is the distance) 

There is no closed form for finding n, but because n^2 is the biggest term, we can simply ignore the others and extract our values for x, y and z thus: 

x = floor(sqrt(M)), y = floor(sqrt(2M)) and finally, z = floor(sqrt(3M)).

On day one he paints a = x meters, the next day he manages b = (y - a) meters, and finally, c = (z - b) meters on the third. 

Update: there is of course always at least one error in every solution... and the above is no exception :) 

So...

x = floor(sqrt(2 M/d)), y = floor(sqrt(2*2M/d)) and finally, z = floor(sqrt(2*3M/d)).

Moral of the story: beware of working with convenient values.