does a program work in all cases?

S

Sheldon

Hi,

This program works when tested with gdb ( see results 1) but when used
in a larger program where 12 becomes 1500 there exists a problem when
freeing the memory ( see results 2). Can anyone give any advise here?
--------------------------------------------------
#include <stdlib.h>
#include <stdio.h>

int main(void) {
int i;
char** arr;

arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);
}
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}
for (i = 0; i < 12; i++) {
strcpy(arr,"Thi");
printf("Arr[%d]\t%s\n",i, arr);
}
for (i = 0; i < 12; i++) {
free(arr);
}
free(arr);
return 1;
}
---------------------------------------------

Result 1:

% gdb a.out
GNU gdb 6.0-2mdk (Mandrake Linux)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i586-mandrake-linux-gnu"...Using host
libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) run
Starting program: a.out
Arr[0] Thi
Arr[1] Thi
Arr[2] Thi
Arr[3] Thi
Arr[4] Thi
Arr[5] Thi
Arr[6] Thi
Arr[7] Thi
Arr[8] Thi
Arr[9] Thi
Arr[10] Thi
Arr[11] Thi

Program exited with code 01.
(gdb)

Results 2:

free(): invalid pointer 0x40426814!
free(): invalid pointer 0x40442c74!
free(): invalid pointer 0x40426874!
free(): invalid pointer 0x40442c54!
free(): invalid pointer 0x404268d4!
free(): invalid pointer 0x40442cb4!

This problem eludes me. Any help is appreciated.

/S
 
C

Chris McDonald

Sheldon said:
int i;
char** arr;
arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);
}
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}



Probably not the cause of your problem,
but you should check for allocation failure of 'arr' immediately after you
attempt the allocation, and certainly before you access arr.
 
B

Ben C

Hi,

This program works when tested with gdb ( see results 1) but when used
in a larger program where 12 becomes 1500 there exists a problem when
freeing the memory ( see results 2). Can anyone give any advise here?

Are you sure you changed all the "12"s to "1500"s?

I would expect the program to work OK, although I've made one or two
comments below you didn't ask for :)

Also need said:
int main(void) {
int i;
char** arr;

arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);


You don't check these allocations...
}
if (!(arr)) {
printf("Failed to allocate memory\n");

....even though you do check this one, but only after using it, which is
a bit late.

You also should really go if (arr != NULL) because !NULL is not
necessarily true on all platforms.

And you could consider printing the error to stderr rather than stdout.
return 0;

Usually 0 is returned for success, not failure.
}
for (i = 0; i < 12; i++) {
strcpy(arr,"Thi");
printf("Arr[%d]\t%s\n",i, arr);
}
for (i = 0; i < 12; i++) {
free(arr);
}
free(arr);
return 1;


Usually 0 is returned for success, not failure.

And for portability, I think I've read here you should only return 0,
EXIT_SUCCESS or EXIT_FAILURE from main.
 
S

Sheldon

Chris McDonald skrev:
Sheldon said:
int i;
char** arr;
arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);
}
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}



Probably not the cause of your problem,
but you should check for allocation failure of 'arr' immediately after you
attempt the allocation, and certainly before you access arr.


I thought I did that with:
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}
Is this not the same as
if(arr==NULL) {
printf("Failed to allocate memory\n");
return 0;
}
?

/S
 
S

Sheldon

Ben C skrev:
Hi,

This program works when tested with gdb ( see results 1) but when used
in a larger program where 12 becomes 1500 there exists a problem when
freeing the memory ( see results 2). Can anyone give any advise here?

Are you sure you changed all the "12"s to "1500"s?

I would expect the program to work OK, although I've made one or two
comments below you didn't ask for :)

Also need said:
int main(void) {
int i;
char** arr;

arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);


You don't check these allocations...
}
if (!(arr)) {
printf("Failed to allocate memory\n");

...even though you do check this one, but only after using it, which is
a bit late.

You also should really go if (arr != NULL) because !NULL is not
necessarily true on all platforms.

And you could consider printing the error to stderr rather than stdout.
return 0;

Usually 0 is returned for success, not failure.
}
for (i = 0; i < 12; i++) {
strcpy(arr,"Thi");
printf("Arr[%d]\t%s\n",i, arr);
}
for (i = 0; i < 12; i++) {
free(arr);
}
free(arr);
return 1;


Usually 0 is returned for success, not failure.

And for portability, I think I've read here you should only return 0,
EXIT_SUCCESS or EXIT_FAILURE from main.


Ok, thanks. I will make the necessary changes and yes 12 was changed to
1500. I am sure of it.

/S
 
C

Chris McDonald

Chris McDonald skrev:
Sheldon said:
int i;
char** arr;
arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);
}
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}



Probably not the cause of your problem,
but you should check for allocation failure of 'arr' immediately after you
attempt the allocation, and certainly before you access arr.

I thought I did that with:
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}
Is this not the same as
if(arr==NULL) {
printf("Failed to allocate memory\n");
return 0;
}

You access/write arr *before* you check if the allocation of arr
was a success.
 
K

Keith Thompson

Ben C said:
if (!(arr)) {
printf("Failed to allocate memory\n");
[...]
You also should really go if (arr != NULL) because !NULL is not
necessarily true on all platforms.

Yes, it is. The expressions (arr != NULL) and (!arr) are exactly
equivalent, assuming arr is a pointer.
 
S

Sheldon

Chris McDonald skrev:
Chris McDonald skrev:
int i;
char** arr;

arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);
}
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}


Probably not the cause of your problem,
but you should check for allocation failure of 'arr' immediately after you
attempt the allocation, and certainly before you access arr.

I thought I did that with:
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}
Is this not the same as
if(arr==NULL) {
printf("Failed to allocate memory\n");
return 0;
}

You access/write arr *before* you check if the allocation of arr
was a success.


Ok, I see now

Will make the change.
/S
 
S

Spiros Bousbouras

Ben said:
...even though you do check this one, but only after using it, which is
a bit late.

You also should really go if (arr != NULL) because !NULL is not
necessarily true on all platforms.

NULL is 0 or (void *) 0 and paragraph 5 of 6.5.3.3
of N1124 says that applying the ! operator to a zero
value gives 1. So !NULL will be true on all conforming
platforms.
 
W

Walter Roberson

NULL is 0 or (void *) 0 and paragraph 5 of 6.5.3.3
of N1124 says that applying the ! operator to a zero
value gives 1. So !NULL will be true on all conforming
platforms.

No, NULL is *not* necessarily 0 or (void *)0 : it can have
any internal representation the compiler desires. What the
standard promises is that it will *compare* equal to 0.
Meanwhile !p is just shorthand for p!=0 and as NULL must compare
equal to 0, p!=0 must be false if p is NULL.

It's the same end result, but the internal details are
different than you are implying.
 
P

pete

Sheldon said:
Hi,

This program works when tested with gdb ( see results 1) but when used
in a larger program where 12 becomes 1500 there exists a problem when
freeing the memory ( see results 2). Can anyone give any advise here?
--------------------------------------------------
#include <stdlib.h>
#include <stdio.h>

int main(void) {
int i;
char** arr;

arr = malloc(sizeof(char *)*12);
for (i = 0; i < 12; i++) {
arr = malloc(sizeof(char)*5);
}
if (!(arr)) {
printf("Failed to allocate memory\n");
return 0;
}
for (i = 0; i < 12; i++) {
strcpy(arr,"Thi");
printf("Arr[%d]\t%s\n",i, arr);
}
for (i = 0; i < 12; i++) {
free(arr);
}
free(arr);
return 1;
}


/* BEGIN new.c */

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

#define NUMBER 12
#define STRING "Thi"

int main(void)
{
int i;
char** arr;

arr = malloc(NUMBER * sizeof *arr);
if (arr == NULL) {
puts("Failed to allocate memory");
exit(EXIT_FAILURE);
}
for (i = 0; i < NUMBER; i++) {
arr = malloc(sizeof STRING);
if (arr == NULL) {
while (i-- != 0) {
free(arr);
}
free(arr);
arr = NULL;
}
}
if (arr == NULL) {
puts("Failed to allocate memory");
exit(EXIT_FAILURE);
}
for (i = 0; i < NUMBER; i++) {
strcpy(arr, STRING);
printf("Arr[%d]\t%s\n", i, arr);
}
for (i = 0; i < NUMBER; i++) {
free(arr);
}
free(arr);
return 0;
}

/* END new.c */
 
M

malc

Ben C wrote:
[..snip..]
NULL is 0 or (void *) 0 and paragraph 5 of 6.5.3.3
of N1124 says that applying the ! operator to a zero
value gives 1. So !NULL will be true on all conforming
platforms.

No, NULL is *not* necessarily 0 or (void *)0 : it can have
any internal representation the compiler desires. What the
standard promises is that it will *compare* equal to 0.
Meanwhile !p is just shorthand for p!=0 and as NULL must compare
equal to 0, p!=0 must be false if p is NULL.

I doubt that `!p' is a shorthand for `p != 0' (atleast according to my
reading of the standards text)
It's the same end result, but the internal details are
different than you are implying.

For quite some time i wanted to know if applying unary operator `!' to
a value of a pointer type will behave like implicit comparison with a
null pointer constant. After studying n869 i am not convinced, perhaps
someone would be kind enough to clarify the issue?

<quote>
6.2.5 Types

....

[#21] Integer and floating types are collectively called
arithmetic types. Arithmetic types and pointer types are
collectively called scalar types. Array and structure types
are collectively called aggregate types.34)
</quote>

<quote>
6.5.3.3 Unary arithmetic operators

....

Constraints

[#1] The operand of the unary + or - operator shall have
arithmetic type; of the ~ operator, integer type; of the !
operator, scalar type.

....

[#5] The result of the logical negation operator ! is 0 if
the value of its operand compares unequal to 0, 1 if the
value of its operand compares equal to 0. The result has
type int. The expression !E is equivalent to (0==E).
</quote>

Now, one has a freedom to apply `!' to a value which has a pointer
type (since 6.5.2 says that pointer types are included into scalar
types).

So far so good.

<quote>
6.5.9 Equality operators

....

Constraints

[#2] One of the following shall hold:

....

-- one operand is a pointer and the other is a null
pointer constant.

....

[#5] Otherwise, at least one operand is a pointer. If one
operand is a null pointer constant, it is converted to the
type of the other operand. If one operand is a pointer to
an object or incomplete type and the other is a pointer to a
qualified or unqualified version of void, the former is
converted to the type of the latter.

[#6] Two pointers compare equal if and only if both are null |
pointers, both are pointers to the same object (including a
pointer to an object and a subobject at its beginning) or
function, both are pointers to one past the last element of
the same array object, or one is a pointer to one past the
end of one array object and the other is a pointer to the
start of a different array object that happens to
immediately follow the first array object in the address
space.82)

</quote>

Now taking into account:

<quote>
6.3.2.3 Pointers

....

[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.48) If a null pointer constant is |
converted to a pointer type, the resulting pointer, called a
null pointer, is guaranteed to compare unequal to a pointer
to any object or function.
</quote>

6.5.3.3(5) says that `!E' is equivalent to (0==E) but 6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant. And this
situation does not fall under 6.5.9(5)

If my memory serves me the `null pointer constat' issue was hotly
debated recently (perhaps even on comp.lang.c), but i don't remember
the outcome, and in any case just want to know whether i should
continue using `!' on pointers. Perhaps this was covered in the later
drafts, or other parts of the standard.
 
P

pete

malc wrote:
[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.
6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant.

No, it doesn't suggest that at all.
 
C

CBFalconer

malc said:
.... snip ...

I doubt that `!p' is a shorthand for `p != 0' (atleast according
to my reading of the standards text)

Both are logical operators, and all logical operators return either
0 or 1.
 
M

malc

pete said:
malc said:
[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.
6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant.

No, it doesn't suggest that at all.

Why? The condition is clearly spelled out, the expression must be
cast to type void * to be called null pointer constant.
 
K

Keith Thompson

No, NULL is *not* necessarily 0 or (void *)0 : it can have
any internal representation the compiler desires. What the
standard promises is that it will *compare* equal to 0.
Meanwhile !p is just shorthand for p!=0 and as NULL must compare
equal to 0, p!=0 must be false if p is NULL.

It's the same end result, but the internal details are
different than you are implying.

NULL is a macro; in itself, it has no "internal representation". It
expands to a sequence of tokens; 0 and (void*)0, or rather ((void*)0)
are two of the most likely possibilities.

Most uses of the NULL macro will result in a null pointer value at run
time; applying the unary ! operator to this value will always yield 1.

The distinction between the NULL macro, null pointer constants, and
null pointer values is an important one.
 
P

pete

malc said:
pete said:
malc said:
[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.
6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant.

No, it doesn't suggest that at all.

Why? The condition is clearly spelled out, the expression must be
cast to type void * to be called null pointer constant.

"or" doesn't mean "and must be".

Can you find the word "or" in the quoted text?
 
K

Keith Thompson

malc said:
Now taking into account:

<quote>
6.3.2.3 Pointers

...

[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.48) If a null pointer constant is |
converted to a pointer type, the resulting pointer, called a
null pointer, is guaranteed to compare unequal to a pointer
to any object or function.
</quote>

6.5.3.3(5) says that `!E' is equivalent to (0==E) but 6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant. And this
situation does not fall under 6.5.9(5)

Read 6.3.2.3 again:

An integer constant expression with the value 0, or such an
expression cast to type void *, is called a null pointer constant.

The integer constant 0, without a cast, most certainly is a null
pointer constant.
If my memory serves me the `null pointer constat' issue was hotly
debated recently (perhaps even on comp.lang.c), but i don't remember
the outcome, and in any case just want to know whether i should
continue using `!' on pointers. Perhaps this was covered in the later
drafts, or other parts of the standard.

There's a great deal of confusion about null pointer constants, but
there's really not much room for debate. I know of a couple of subtle
issues with respect to the standard's definition (see below), but
nothing that a typical programmer needs to worry about. Section 5 of
the comp.lang.c FAQ, <http://www.c-faq.com/>, explains null pointers,
null pointer constants, and the NULL macro quite well.

The subtle points (feel free to stop reading right now):

According to the language definition, at least as I interpret it, an
unadorned integer constant 0 is by definition a "null pointer
constant" even if it doesn't appear in a context that requires one.
For example, this:
int x = 0;
contains a null pointer constant, even though there's not a pointer
object or value in sight. This is a bit counterintuitive, but it's
really not a problem; just ignore the fact that it's a null pointer
constant unless you need it to be one.

The definition of a parenthesized expression says that it has certain
of the same properties as the unparenthesized expression, namely its
type, its value, whether it's an lvalue, whether it's a function
designator, and whether it's a void expression. Note that the list of
properties does *not* include whether it's a null pointer constant.
So, strictly speaking, (void*)0 is a null pointer constant, but
((void*)0) is not. But the standard requires definitions of
object-like macros in the standard library to be fully parenthesized
where necessary. So, by a strict reading of the standard, NULL cannot
expand to (void*)0 because it's not fully parenthesized (consider
sizeof NULL), but it can't expand to ((void*)0) because that's not a
null pointer constant. It's obvious, though, that a parenthesized
null pointer constant is *intended* to be a null pointer constant, and
many implementations just go ahead and define NULL as ((void*)0).
(One could argue, I suppose, that treating ((void*)0) as a null
pointer constant is an implementation-specific extension.)
 
M

malc

pete said:
malc said:
pete said:
malc wrote:

[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.

6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant.

No, it doesn't suggest that at all.

Why? The condition is clearly spelled out, the expression must be
cast to type void * to be called null pointer constant.

"or" doesn't mean "and must be".

Can you find the word "or" in the quoted text?

Yes. `or' eluded me completely, thank you for pointing it out.
 
S

Sjouke Burry

pete said:
malc wrote:

[#3] An integer constant expression with the value 0, or
such an expression cast to type void *, is called a null
pointer constant.


6.3.2.3 seems to
suggest that uncasted 0 is not a null pointer constant.


No, it doesn't suggest that at all.
Gentlemen, are you discussing CPLUSPLUS???
Because "zero equals NULL" as far as I know
only applies there.....
 

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,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top