Nothing is wrong. It is working as intended. * resets itself at the beginning of every hour/day/month. Put another way, * is a stand-in for the maximum range of the value in question. So * in the minutes column stands in for 0-59, and */40 means "starting at 0, run every 40 minutes up to 59". See 'Special characters' on the cron Wikipedia page for more info.
What you probably need to do is run the job every 20 minutes, and have the program decide whether or not it should run. Or, do it with two lines
0,40 0,2,4,6,8,10,12,14,16,18,20,22 * * * myshellcommand
20 1,3,5,7,9,11,13,15,17,19,21,23 * * * myshellcommand
Note that this can be written in a slightly more compact form:
0,40 */2 * * * myshellcommand
20 1-23/2 * * * myshellcommand
In this case, */2 indicates every second hour starting from 0 (since * is equivalent to 0-23), and 1-23/2 indicates every second hour starting from hour 1.