Connecting Tech Pros Worldwide Forums | Help | Site Map

Write to dynamic two dimension array outside the range without Segmentation fault

lovecreatesbea...@gmail.com
Guest
 
Posts: n/a
#1: Sep 3 '06
This code snippet is an exercise on allocating two dimension array
dynamically. Though this one is trivial, is it a correct one?
Furthermore, when I tried to make these changes to the original
example:

for (i = 0; i < ROW + 2; ++i){ /*line 14*/
strcpy(array[i], "C! C!"); /*line 15*/

Apparently, the modified code wrote to the memory unit outside the
allocated array, but the program ran well and there was no Segmentation
fault. Thank you.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define ROW 4
#define COL 3

int main(void){
char (*array)[COL];
int i;

array = malloc(ROW * sizeof *array);
if (array){
for (i = 0; i < ROW; ++i){ /*line 14*/
strcpy(array[i], "C!"); /*line 15*/
printf("%s\n", array[i]);
}
}
free(array);

return 0;
}


bwaichu@yahoo.com
Guest
 
Posts: n/a
#2: Sep 3 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



lovecreatesbea...@gmail.com wrote:
Quote:
strcpy(array[i], "C!"); /*line 15*/
printf("%s\n", array[i]);
strcpy doesn't nul terminate, so your call to printf will fault.

Coos Haak
Guest
 
Posts: n/a
#3: Sep 3 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


Op 3 Sep 2006 10:28:48 -0700 schreef bwaichu@yahoo.com:
Quote:
lovecreatesbea...@gmail.com wrote:
>
Quote:
> strcpy(array[i], "C!"); /*line 15*/
> printf("%s\n", array[i]);
>
strcpy doesn't nul terminate, so your call to printf will fault.
strcpy does, memcpy doesn't.
printf won't fail here.
--
Coos
Flash Gordon
Guest
 
Posts: n/a
#4: Sep 3 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


bwaichu@yahoo.com wrote:
Quote:
lovecreatesbea...@gmail.com wrote:
>
Quote:
> strcpy(array[i], "C!"); /*line 15*/
> printf("%s\n", array[i]);
>
strcpy doesn't nul terminate,
What on earth makes you think that? strcpy is a *string* copy, so of
course it is defined to copy the null termination, otherwise it would be
called something like,
CopyJustTooLittleOfAStringToBeUsefull99PercentOfTh eTimeOrMore.
Quote:
so your call to printf will fault.
Even if you were write about strcpy (which you are not) that would still
not guarantee that the call to printf would fault.
--
Flash Gordon
Flash Gordon
Guest
 
Posts: n/a
#5: Sep 3 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


lovecreatesbea...@gmail.com wrote:
Quote:
This code snippet is an exercise on allocating two dimension array
dynamically. Though this one is trivial, is it a correct one?
Furthermore, when I tried to make these changes to the original
example:
>
for (i = 0; i < ROW + 2; ++i){ /*line 14*/
strcpy(array[i], "C! C!"); /*line 15*/
>
Apparently, the modified code wrote to the memory unit outside the
allocated array, but the program ran well and there was no Segmentation
fault. Thank you.
Excuse me mister policeman, but why are you telling me I should not
drive with my eyes close? I just managed to drive 100 yards down the
road with my eyes closed and I didn't crash!

Just because you do something wrong it does not guarantee a crash. All
it guarantees is that you have done something wrong.
Quote:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
>
#define ROW 4
#define COL 3
>
int main(void){
char (*array)[COL];
int i;
>
array = malloc(ROW * sizeof *array);
if (array){
for (i = 0; i < ROW; ++i){ /*line 14*/
strcpy(array[i], "C!"); /*line 15*/
printf("%s\n", array[i]);
}
}
free(array);
>
return 0;
}
For more flexible approaches I suggest you read question 6.16 of the
comp.lang.c FAQ.
--
Flash Gordon
bwaichu@yahoo.com
Guest
 
Posts: n/a
#6: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



Coos Haak wrote:
Quote:
Op 3 Sep 2006 10:28:48 -0700 schreef bwaichu@yahoo.com:
>
Quote:
lovecreatesbea...@gmail.com wrote:
Quote:
strcpy(array[i], "C!"); /*line 15*/
printf("%s\n", array[i]);
strcpy doesn't nul terminate, so your call to printf will fault.
>
strcpy does, memcpy doesn't.
printf won't fail here.
You mis-read my comment. The OP only allocated array[0], so the
designation
array[1] through array[3] has not be allocated. Therefore, when you
strcpy, there is no way you can nul terminate since the designation is
smaller than the string being copied.

bwaichu@yahoo.com
Guest
 
Posts: n/a
#7: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



Here's one that will work since I have allocated the array each
time through the for loop. And strcpy will nul terminate because
the destination is big enough to hold the nul terminator.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main(void) {

char *string[20];
int i;

for (i = 0; i < 4; i++) {
string[i] = calloc(6, sizeof(char));
strcpy(string[i], "hello");
printf("%s\n", string[i]);
}
for (i = 0; i < 4; i++) {
free(string[i]);
}
return 0;
}

lovecreatesbea...@gmail.com
Guest
 
Posts: n/a
#8: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



Flash Gordon wrote:
Quote:
lovecreatesbea...@gmail.com wrote:
Quote:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define ROW 4
#define COL 3

int main(void){
char (*array)[COL];
int i;

array = malloc(ROW * sizeof *array);
if (array){
for (i = 0; i < ROW; ++i){ /*line 14*/
strcpy(array[i], "C!"); /*line 15*/
printf("%s\n", array[i]);
}
}
free(array);

return 0;
}
>
For more flexible approaches I suggest you read question 6.16 of the
comp.lang.c FAQ.
Isn't the approach in my code example flexible enough? Isn't it correct?

exacube@gmail.com
Guest
 
Posts: n/a
#9: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


Isn't the approach in my code example flexible enough? Isn't it correct?

No, it's not. For one,

char (*array)[COL];

Is errorneous. It is different from:

char *array[COL];

You should know that [] precedes the * operator. Insted of creating an
array of pointers to characters, you created a pointer to an array of
characters. See the difference?

Vardhan

websnarf@gmail.com
Guest
 
Posts: n/a
#10: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


lovecreatesbea...@gmail.com wrote:
Quote:
This code snippet is an exercise on allocating two dimension array
dynamically. Though this one is trivial, is it a correct one?
Yes, its a 2 dimensional storage used for holding a 1 dimensional array
of C strings, being filled then output one at a time.
Quote:
Furthermore, when I tried to make these changes to the original
example:
>
for (i = 0; i < ROW + 2; ++i){ /*line 14*/
strcpy(array[i], "C! C!"); /*line 15*/
>
Apparently, the modified code wrote to the memory unit outside the
allocated array, but the program ran well and there was no Segmentation
fault. Thank you.
Yes, this is called a buffer overflow. array is defined for ROW (== 4)
rows only, not ROW+2 rows. Furthermore each row can hold at most 3
characters, even though storing "C! C!" requires 6 characters. You can
read more about this condition here:

http://en.wikipedia.org/wiki/Buffer_overflow

Just because there happened to be valid memory past the end of your
well defined objects doesn't mean that accessing them is valid. The
lack of a Segmentation fault is not proof of correctness. (In fact
more buffer overflows in real world programs do not lead to immediate
Segmentation Faults.)
Quote:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
>
#define ROW 4
#define COL 3
>
int main(void){
char (*array)[COL];
int i;
>
array = malloc(ROW * sizeof *array);
if (array){
for (i = 0; i < ROW; ++i){ /*line 14*/
strcpy(array[i], "C!"); /*line 15*/
printf("%s\n", array[i]);
}
}
free(array);
>
return 0;
}
--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

lovecreatesbea...@gmail.com
Guest
 
Posts: n/a
#11: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



bwaichu@yahoo.com wrote:
Quote:
You mis-read my comment. The OP only allocated array[0], so the
designation
array[1] through array[3] has not be allocated. Therefore, when you
strcpy, there is no way you can nul terminate since the designation is
smaller than the string being copied.
You did not quote the enough related code of mine. I quote it below
with a change of locating the free invoke inside the if statement. In
my original allocation for the two dimensional array:

sizeof *array == COL * sizeof (char),
it's enough for holding a single element array[i];

ROW * sizeof *array == ROW * COL * sizeof (char),
this is the amount of the space for ROW rows of array[i].

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define ROW 4
#define COL 3

int main(void){
char (*array)[COL];
int i;

array = malloc(ROW * sizeof *array);
if (array){
for (i = 0; i < ROW; ++i){
strcpy(array[i], "C!");
printf("%s\n", array[i]);
}
free(array);
}

return 0;
}

lovecreatesbea...@gmail.com
Guest
 
Posts: n/a
#12: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


lovecreatesbea...@gmail.com wrote:
Quote:
bwaichu@yahoo.com wrote:
Quote:
You mis-read my comment. The OP only allocated array[0], so the
designation
array[1] through array[3] has not be allocated. Therefore, when you
strcpy, there is no way you can nul terminate since the designation is
smaller than the string being copied.
>
You did not quote the enough related code of mine. I quote it below
with a change of locating the free invoke inside the if statement. In
my original allocation for the two dimensional array:
>
sizeof *array == COL * sizeof (char),
it's enough for holding a single element array[i];
>
ROW * sizeof *array == ROW * COL * sizeof (char),
this is the amount of the space for ROW rows of array[i].
The proper size of memory has been allocated, and then I can access the
elements one by one. This is similar to what you can do with a dynamic
one dimensional array.

int *dynarray;
dynarray = malloc(10 * sizeof(int));
dynarray[0] = 0;
...
dynarray[9] = 0;
Quote:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
>
#define ROW 4
#define COL 3
>
int main(void){
char (*array)[COL];
int i;
>
array = malloc(ROW * sizeof *array);
if (array){
for (i = 0; i < ROW; ++i){
strcpy(array[i], "C!");
printf("%s\n", array[i]);
}
free(array);
}
>
return 0;
}
Flash Gordon
Guest
 
Posts: n/a
#13: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


lovecreatesbea...@gmail.com wrote:
Quote:
Flash Gordon wrote:
Quote:
>lovecreatesbea...@gmail.com wrote:
<snip attempt at multi-dimensional array>
Quote:
Quote:
>For more flexible approaches I suggest you read question 6.16 of the
>comp.lang.c FAQ.
>
Isn't the approach in my code example flexible enough? Isn't it correct?
Have you read the FAQ question I pointed you at? What have you failed to
understand in the answer it provides? I'm not going to bother rehashing
what is explained so well there when you seem not to have bothered to
read it.
--
Flash Gordon
lovecreatesbea...@gmail.com
Guest
 
Posts: n/a
#14: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


Flash Gordon wrote:
Quote:
lovecreatesbea...@gmail.com wrote:
Quote:
Flash Gordon wrote:
Quote:
lovecreatesbea...@gmail.com wrote:
>
<snip attempt at multi-dimensional array>
>
Quote:
Quote:
For more flexible approaches I suggest you read question 6.16 of the
comp.lang.c FAQ.
Isn't the approach in my code example flexible enough? Isn't it correct?
>
Have you read the FAQ question I pointed you at? What have you failed to
understand in the answer it provides? I'm not going to bother rehashing
what is explained so well there when you seem not to have bothered to
read it.
Hello, Mr. Gordon, Thank you. Is my original code correct?

That faq list is very good. I read it frequently and have made a local
copy by wget tool. Thank the author and others. It mentions:

"Yet another option is to use pointers to arrays:

int (*array4)[NCOLUMNS] = malloc(nrows * sizeof(*array4));"

This is the method I used in my code example, right?

Coos Haak
Guest
 
Posts: n/a
#15: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


Op 3 Sep 2006 16:17:17 -0700 schreef bwaichu@yahoo.com:
Quote:
Coos Haak wrote:
Quote:
>Op 3 Sep 2006 10:28:48 -0700 schreef bwaichu@yahoo.com:
>>
Quote:
>>lovecreatesbea...@gmail.com wrote:
>>>
>>> strcpy(array[i], "C!"); /*line 15*/
>>> printf("%s\n", array[i]);
>>>
>>strcpy doesn't nul terminate, so your call to printf will fault.
>>
>strcpy does, memcpy doesn't.
>printf won't fail here.
>
You mis-read my comment. The OP only allocated array[0], so the
designation
array[1] through array[3] has not be allocated. Therefore, when you
strcpy, there is no way you can nul terminate since the designation is
smaller than the string being copied.
You write nonsense here, strcpy _always_ terminates with a null, even if
the string to copy has zero length. memcpy won't copy anything in this
case. The allocation may have been bad, but that is not my point.
--
Coos
bwaichu@yahoo.com
Guest
 
Posts: n/a
#16: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



Coos Haak wrote:
Quote:
Quote:
You mis-read my comment. The OP only allocated array[0], so the
designation
array[1] through array[3] has not be allocated. Therefore, when you
strcpy, there is no way you can nul terminate since the designation is
smaller than the string being copied.
>
You write nonsense here, strcpy _always_ terminates with a null, even if
the string to copy has zero length. memcpy won't copy anything in this
case. The allocation may have been bad, but that is not my point.
The function strcpy will attempt to nul terminate, but if the space
isn't big enough,
it might seg fault. I am not arguing that strcpy does not nul
terminate. I am
saying that in the OP's code there is no way for strcpy to nul
terminate because
it does not have any allocated space to write to.

Flash Gordon
Guest
 
Posts: n/a
#17: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


lovecreatesbea...@gmail.com wrote:
Quote:
Flash Gordon wrote:
Quote:
>lovecreatesbea...@gmail.com wrote:
Quote:
>>Flash Gordon wrote:
>>>lovecreatesbea...@gmail.com wrote:
><snip attempt at multi-dimensional array>
>>
Quote:
>>>For more flexible approaches I suggest you read question 6.16 of the
>>>comp.lang.c FAQ.
>>Isn't the approach in my code example flexible enough? Isn't it correct?
>Have you read the FAQ question I pointed you at? What have you failed to
>understand in the answer it provides? I'm not going to bother rehashing
>what is explained so well there when you seem not to have bothered to
>read it.
>
Hello, Mr. Gordon, Thank you. Is my original code correct?
I can't remember your original code. However, if I pointed out no errors
in it then I probably did not spot any.
Quote:
That faq list is very good. I read it frequently and have made a local
copy by wget tool. Thank the author and others. It mentions:
OK, had you said that you had read it I would not have commented.
Quote:
"Yet another option is to use pointers to arrays:
>
int (*array4)[NCOLUMNS] = malloc(nrows * sizeof(*array4));"
>
This is the method I used in my code example, right?
If that is the method you used, then yes it is valid. However, it is
less flexible than the other methods because you have to determine at
compile time the number of columns instead of being able to set it at
run time. Which methods are flexible enough depends on the exact
requirements and I can no longer remember what the OPs exact
requirements where.
--
Flash Gordon.
bwaichu@yahoo.com
Guest
 
Posts: n/a
#18: Sep 4 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



lovecreatesbea...@gmail.com wrote:
Quote:
That faq list is very good. I read it frequently and have made a local
copy by wget tool. Thank the author and others. It mentions:
>
"Yet another option is to use pointers to arrays:
>
int (*array4)[NCOLUMNS] = malloc(nrows * sizeof(*array4));"
>
This is the method I used in my code example, right?
Nope. Look at that code.

Now, look at your code. How many integers in the above code can be
written per row and why? Where are you allocating space for the
characters you want to string copy in your code? How do you increase or
decrease the number of characters you want to allocate in your code?
How do you access the beginning of each string after you have string
copied it? I suggest drawing it out.

Here's a refresher on pointers for you:

http://cslibrary.stanford.edu/102/

Barry Schwarz
Guest
 
Posts: n/a
#19: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


On 3 Sep 2006 16:17:17 -0700, "bwaichu@yahoo.com" <bwaichu@yahoo.com>
wrote:
Quote:
>
>Coos Haak wrote:
Quote:
>Op 3 Sep 2006 10:28:48 -0700 schreef bwaichu@yahoo.com:
>>
Quote:
lovecreatesbea...@gmail.com wrote:
>
> strcpy(array[i], "C!"); /*line 15*/
> printf("%s\n", array[i]);
>
strcpy doesn't nul terminate, so your call to printf will fault.
>>
>strcpy does, memcpy doesn't.
>printf won't fail here.
>
>You mis-read my comment. The OP only allocated array[0], so the
>designation
>array[1] through array[3] has not be allocated. Therefore, when you
>strcpy, there is no way you can nul terminate since the designation is
>smaller than the string being copied.
No, it is you who misread the original code. The object named array
is a pointer to an array of three char. It is initialized to point to
a dynamically allocated area of memory which has room for four such
arrays.

The expression array[i] is the i-th array in the allocated memory. In
the context in which it is used, it evaluates to the address of
array[i][0] with type pointer to char. Since strcpy is copying only
three characters, they will fit it array[i] and both strcpy and printf
will behave.


Remove del for email
Barry Schwarz
Guest
 
Posts: n/a
#20: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


On 3 Sep 2006 16:36:05 -0700, "bwaichu@yahoo.com" <bwaichu@yahoo.com>
wrote:
Quote:
>
>Here's one that will work since I have allocated the array each
It would be nice if you quoted enough of the original thread to
indicate one what.
Quote:
>time through the for loop. And strcpy will nul terminate because
>the destination is big enough to hold the nul terminator.
Unless you invoke undefined behavior, strcpy will always nul
terminate.
Quote:
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <string.h>
>
>int
>main(void) {
>
> char *string[20];
Why 20 when you only use 4?
Quote:
> int i;
>
> for (i = 0; i < 4; i++) {
> string[i] = calloc(6, sizeof(char));
Why calloc when you immediately copy a string into the allocated
memory?

sizeof(char) is always 1.
Quote:
> strcpy(string[i], "hello");
> printf("%s\n", string[i]);
> }
> for (i = 0; i < 4; i++) {
> free(string[i]);
> }
> return 0;
>}

Remove del for email
Barry Schwarz
Guest
 
Posts: n/a
#21: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


On 3 Sep 2006 19:42:56 -0700, exacube@gmail.com wrote:
Quote:
Quote:
>Isn't the approach in my code example flexible enough? Isn't it correct?
>
>No, it's not. For one,
>
>char (*array)[COL];
>
>Is errorneous. It is different from:
His definition is not erroneous. He defines a pointer to an array and
uses it to reference the arrays it points to.
Quote:
>
>char *array[COL];
>
>You should know that [] precedes the * operator. Insted of creating an
>array of pointers to characters, you created a pointer to an array of
>characters. See the difference?
While what you say is true, it has nothing to do with his code.


Remove del for email
Barry Schwarz
Guest
 
Posts: n/a
#22: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


On 3 Sep 2006 10:02:11 -0700, "lovecreatesbea...@gmail.com"
<lovecreatesbeauty@gmail.comwrote:
Quote:
>This code snippet is an exercise on allocating two dimension array
>dynamically. Though this one is trivial, is it a correct one?
>Furthermore, when I tried to make these changes to the original
>example:
>
for (i = 0; i < ROW + 2; ++i){ /*line 14*/
strcpy(array[i], "C! C!"); /*line 15*/
>
>Apparently, the modified code wrote to the memory unit outside the
>allocated array, but the program ran well and there was no Segmentation
>fault. Thank you.
snip code

One of the unluckiest manifestations of undefined behavior is to
appear to work as intended.


Remove del for email
bwaichu@yahoo.com
Guest
 
Posts: n/a
#23: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



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. The same
holds true for strncpy.

Here's some example code, where strcpy does not nul terminate. I have
left out the test for calloc's (replaced the OP's malloc) success, and
I have left out the free'ing as the OP had done in their code.

#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[i], "hello");
printf("%s\n", string[i]);
}
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.

I hope this explanation is better than just saying that strcpy does not
nul terminate. The changes suggested in the OP's message would write
to unallocated space. The for loop would try to strcpy to ROW's that
haven't been allocated.

Richard Bos
Guest
 
Posts: n/a
#24: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


"bwaichu@yahoo.com" <bwaichu@yahoo.comwrote:
Quote:
Coos Haak wrote:
>
Quote:
Quote:
You mis-read my comment. The OP only allocated array[0], so the
designation
array[1] through array[3] has not be allocated. Therefore, when you
strcpy, there is no way you can nul terminate since the designation is
smaller than the string being copied.
You write nonsense here, strcpy _always_ terminates with a null, even if
the string to copy has zero length. memcpy won't copy anything in this
case. The allocation may have been bad, but that is not my point.
>
The function strcpy will attempt to nul terminate, but if the space
isn't big enough, it might seg fault.
The same is true for any other character that strcpy() writes. If you
wanted to say that strcpy() has undefined behaviour if it is made to
write to memory that has not been properly allocated, that's what you
should have written. This claptrap about null termination is just that:
balderdash.

Richard
Barry Schwarz
Guest
 
Posts: n/a
#25: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


On 4 Sep 2006 16:45:19 -0700, "bwaichu@yahoo.com" <bwaichu@yahoo.com>
wrote:
Quote:
>
>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. The same
>holds true for strncpy.
If you use any function to move data into a space too small for that
data, you invoke undefined behavior.
Quote:
>
>Here's some example code, where strcpy does not nul terminate. I have
>left out the test for calloc's (replaced the OP's malloc) success, and
>I have left out the free'ing as the OP had done in their code.
>
>#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[i], "hello");
> printf("%s\n", string[i]);
> }
> exit(EXIT_SUCCESS);
>}
>
>If I run this, it will print out hello four times. But that doesn't
If you run this, you invoke undefined behavior. It doesn't matter
what the results are on your system because we are no longer in the
realm of C.
Quote:
>mean it works. COL can only hold 3 characters plus a nul per row.
You meant string, not COL. In this particular case, string points to
an allocated block of memory which is 16 bytes. When i is 0, the
strcpy and the printf will reference bytes 0 through 5, When i is 1,
they use bytes 4 through 9. When i is 2, They use bytes 8 through 13.
All these operations are well defined. When i is 3, they attempt to
use bytes 12 through 17. This is undefined behavior.



Remove del for email
Chris Torek
Guest
 
Posts: n/a
#26: Sep 5 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


In article <1157413519.473744.197160@m79g2000cwm.googlegroups .com>
bwaichu@yahoo.com <bwaichu@yahoo.comwrote:
Quote:
>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]
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[i], "hello");
printf("%s\n", string[i]);
}
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.
Quote:
>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".
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
bwaichu@yahoo.com
Guest
 
Posts: n/a
#27: Sep 6 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault



Barry Schwarz wrote:
Quote:
You meant string, not COL. In this particular case, string points to
an allocated block of memory which is 16 bytes. When i is 0, the
strcpy and the printf will reference bytes 0 through 5, When i is 1,
they use bytes 4 through 9. When i is 2, They use bytes 8 through 13.
All these operations are well defined. When i is 3, they attempt to
use bytes 12 through 17. This is undefined behavior.
You are explanation is far better than mine. Is the right answer all
ways undefined behavior when the program is written in a way, where the
C programming language is no longer clear as to what happens?

Barry Schwarz
Guest
 
Posts: n/a
#28: Sep 7 '06

re: Write to dynamic two dimension array outside the range without Segmentation fault


On 6 Sep 2006 09:33:47 -0700, "bwaichu@yahoo.com" <bwaichu@yahoo.com>
wrote:
Quote:
>
>Barry Schwarz wrote:
>
Quote:
>You meant string, not COL. In this particular case, string points to
>an allocated block of memory which is 16 bytes. When i is 0, the
>strcpy and the printf will reference bytes 0 through 5, When i is 1,
>they use bytes 4 through 9. When i is 2, They use bytes 8 through 13.
>All these operations are well defined. When i is 3, they attempt to
>use bytes 12 through 17. This is undefined behavior.
>
>You are explanation is far better than mine. Is the right answer all
>ways undefined behavior when the program is written in a way, where the
>C programming language is no longer clear as to what happens?
The standard identifies several different types of behavior: defined,
unspecified, undefined, implementation defined, and possibly others.

Clarity on the other hand is pretty subjective, confirmed by many of
the wandering threads in this group.


Remove del for email
Closed Thread