Let me clarify what I had written before. I had said that strcpy would
not nul terminate. Now, the fuction in theory should nul terminate.
This is not true if the space being written to is smaller.
Well, yes and no:
char buf[4]; /* can hold "abc" */
strcpy(buf, "supercalifragialisticexpialidocious"); /* ERROR */
The effect of this call to strcpy() is undefined, because the
call "wants" to write 36 "C bytes" ("char"s) into a four-character
array.
In practice, on most real machines, it really *does* write all 36
bytes (35 letters plus '\0' byte) into the four-character array,
overwriting 32 other bytes. Subsequent behavior depends on what
was in those "other" bytes, and how important they were. Of course,
since the behavior is undefined, the C Standards say nothing about
what has to happen, so whatever *does* happen is the programmer's
problem, not the implementation's.
In the case when what *does* happen is "the program continues to
run", if you stop the program with some external agent and inspect
the array named "buf", it is true that it will not hold a '\0'-terminated
C string. Instead, it will hold the first four characters of the
copied string -- in this case 's', 'u', 'p', and 'e'. This is
precisely what you see when you use your debugger:
[I need to quote the entire code, or change it; for time reasons on
my part, I will just quote]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#define COL 4
#define ROW 4
int
main(void) {
int i;
char (*string)[COL] = calloc(ROW, sizeof *string);
for (i = 0; i < ROW; i++) {
strcpy(string, "hello");
printf("%s\n", string);
}
exit(EXIT_SUCCESS);
}
If I run this, it will print out hello four times. But that doesn't
mean it works. COL can only hold 3 characters plus a nul per row.
So when I run this through gdb, I see:
Breakpoint 1 at 0x4008ce: file string.c, line 20.
(gdb) run
Starting program: /home/user/string
hello
hello
hello
hello
Breakpoint 1, main () at string.c:20
20 exit(EXIT_SUCCESS);
(gdb) p *string
$1 = "hell"
(gdb) p/x string[0]
$2 = {0x68, 0x65, 0x6c, 0x6c}
(gdb)
As you can see, there is no nul terminator. The space was only large
enough to hold 4 characters. The remaining characters overwrote the
buffer space. But the program still appeared to work as seen by the
hello's printing.
And in fact, what happened on your machine (which I can predict
due to my Amazing Psychic Abilities ) is that calloc(4,4)
actually obtained more than 16 bytes, and each of the strcpy()
calls put six bytes into the corresponding four-byte region, with
the "extra two bytes" writing over the next array entry (when i
\elem {0,1,2}) or some of the "spare" bytes calloc() got (when
i==3). The printf() calls accessed all six bytes of each four-byte
region (including the two that extend past the region). The
debugger, however, is much smarter than the C runtime library, and
even if you print string[3], it will only access the "proper four"
of the six bytes written into corresponding four-byte region.
Note also that:
char buf16[16];
strcpy(&buf16[0], "hello");
strcpy(&buf16[4], "hello");
is well-defined, and puts the string "hellhello" into the 16-byte
buffer "buf16". The first strcpy() does in fact write a complete
string; the second strcpy() then overwrites part of the first,
writing a new complete string that makes the previous string
longer.
If you then do:
printf("%.4s\n", &buf[0]);
the output will be "hell\n", not "hellhello\n" -- and gdb essentially
does just this.
I hope this explanation is better than just saying that strcpy does not
nul terminate.
It just goes to show that, when there is undefined behavior,
*anything* can happen, including "it seems to work, but the debugger
-- which does different things from the C library -- shows different
results".