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

  • Thread starter lovecreatesbea...
  • Start date
L

lovecreatesbea...

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, "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, "C!"); /*line 15*/
printf("%s\n", array);
}
}
free(array);

return 0;
}
 
F

Flash Gordon

strcpy(array, "C!"); /*line 15*/
printf("%s\n", array);


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,
CopyJustTooLittleOfAStringToBeUsefull99PercentOfTheTimeOrMore.
> 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.
 
F

Flash Gordon

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, "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.
#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, "C!"); /*line 15*/
printf("%s\n", array);
}
}
free(array);

return 0;
}


For more flexible approaches I suggest you read question 6.16 of the
comp.lang.c FAQ.
 
B

bwaichu

Coos said:
Op 3 Sep 2006 10:28:48 -0700 schreef (e-mail address removed):
strcpy(array, "C!"); /*line 15*/
printf("%s\n", array);


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.
 
B

bwaichu

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 = calloc(6, sizeof(char));
strcpy(string, "hello");
printf("%s\n", string);
}
for (i = 0; i < 4; i++) {
free(string);
}
return 0;
}
 
L

lovecreatesbea...

Flash said:
#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, "C!"); /*line 15*/
printf("%s\n", array);
}
}
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?
 
E

exacube

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
 
W

websnarf

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.
Furthermore, when I tried to make these changes to the original
example:

for (i = 0; i < ROW + 2; ++i){ /*line 14*/
strcpy(array, "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.)
#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, "C!"); /*line 15*/
printf("%s\n", array);
}
}
free(array);

return 0;
}
 
F

Flash Gordon

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.
 
L

lovecreatesbea...

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;

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

#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, "C!");
printf("%s\n", array);
}
free(array);
}

return 0;
}
 
L

lovecreatesbea...

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;

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


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;
#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, "C!");
printf("%s\n", array);
}
free(array);
}

return 0;
}
 
L

lovecreatesbea...

Flash said:
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?
 
C

Coos Haak

Op 3 Sep 2006 16:17:17 -0700 schreef (e-mail address removed):
Coos said:
Op 3 Sep 2006 10:28:48 -0700 schreef (e-mail address removed):
(e-mail address removed) wrote:

strcpy(array, "C!"); /*line 15*/
printf("%s\n", array);

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.
 
F

Flash Gordon

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.
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.
"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.
 
B

bwaichu

Coos said:
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.
 
B

bwaichu

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/
 
B

Barry Schwarz

Coos said:
Op 3 Sep 2006 10:28:48 -0700 schreef (e-mail address removed):
(e-mail address removed) wrote:

strcpy(array, "C!"); /*line 15*/
printf("%s\n", array);

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


Remove del for email
 
B

Barry Schwarz

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.
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.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main(void) {

char *string[20];

Why 20 when you only use 4?
int i;

for (i = 0; i < 4; i++) {
string = calloc(6, sizeof(char));


Why calloc when you immediately copy a string into the allocated
memory?

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



Remove del for email
 

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,770
Messages
2,569,586
Members
45,082
Latest member
KetonaraKetoACV

Latest Threads

Top