trying to make my "fillvalues" function work...

  • Thread starter =?ISO-8859-1?Q?Martin_J=F8rgensen?=
  • Start date
M

Micah Cowan

Martin Jørgensen said:
Perhaps a stupid question, but what's those __FILE__, __LINE__ (,
__func__ things?

__FILE__ and __LINE__ are special "macro"-like identifiers that the
preprocessor automatically replaces with the name of the file and the
line number (respectively) in which they appeared. These have been
around forever(?).

There is no "(" thing... Michael was just trying to include the tail
end of the list (consisting of just __func__) into the parentheses.

__func__ is new to C99, and is similar to the other two: the
difference is that it's not handled during preprocessing: it's an
actual variable defined in every function (well, in practice it's only
defined in functions that actually refer to it).

The only practical difference in usage between __FILE__ and __func__
is that you can use __FILE__ with the preprocessor's
string-concatenation feature to do:

fputs(__FILE__ ": this file has sucky code.\n", stderr);

whereas with __func__, since it resolves to an actual object, you have
to do something like:

fprintf(stderr, "%s: this function does, too.\n", __func__);

-Micah
 
M

Michael Mair

Martin said:
Perhaps a stupid question, but what's those __FILE__, __LINE__ (,
__func__ things?

__FILE__ and __LINE__ are predefined macro names giving you the
current file and line; you can set the current file/line with the
#line directive. Just look it up in your C text book.
There are other predefined macros for time, to find out whether you
have standard C and if yes, which version etc.
C99 adds __func__, which gives you the name of the current function.
Well, I think you're much more advanced than me when you think about
generating a location... My "location" is just a char-array:

int **array = malloc((nx+1)*sizeof(int*));
checkPtr_error("array", &array)

Here "array" is the "location" and "array" will be printed if this is
the location where memory couldn't be allocated.

Nonetheless, there is not much benefit in such a checkPtr_error()
function -- it still does not handle the error nicely. Different
places in your code may give you a chance to salvage your work
or may facilitate terminating orderly or lend themselves to aborting
only.
I might be stupid or too unexperienced with C-programming but I still
don't get that. The following works, right: if (NULL == ptr) {.....}

So doing either:

1 || ptd == NULL

or:

"0 && ptd != NULL"

I don't understand what that does... In the first case: if(1 || ptd ==
NULL) would always give 1, becuase || = logical "or" right? 1 = true,
AFAIR.

In the second case: if(0 && ptd != NULL) that would always give 0
because && means logical "and", right?

Yes. This is what I am talking about: 1 || whatever is always true,
0 && whatever is always false; "whatever" is not evaluated.
I just wanted to illustrate _how_ you can make sure that your
error handling is activated. Writing "1 || " in front of "ptd == NULL"
is nicer than replacing it by "1" as it saves the original expression.
There are more sophisticated ways of going about it, of course,
but allocating a very large amount of memory, e.g. (size_t)-2 bytes,
or switching your error catching ifs to true are good examples.

The main thing is: Test your error handling code. Many people don't
but essentially this is your last line of defense. If you have waited
several days for the result of a lengthy computation and it dies
literally during the last iteration, then you are certainly unhappy
if insufficient error handling eats the result dump or restart data.

Cheers
Michael
 
S

stathis gotsis

Martin Jørgensen said:
I might be stupid or too unexperienced with C-programming but I still
don't get that. The following works, right: if (NULL == ptr) {.....}

So doing either:

1 || ptd == NULL

or:

"0 && ptd != NULL"

I don't understand what that does... In the first case: if(1 || ptd ==
NULL) would always give 1, becuase || = logical "or" right? 1 = true,
AFAIR.

Yes that expression always yields 1, which equals to true in a logical
context. Altering the condition in this way can show you how your error
handling works. That is because the (compound) statement under if will be
executed, which would be executed only in the case of allocation failure
otherwise.
 
K

Keith Thompson

Micah Cowan said:
__FILE__ and __LINE__ are special "macro"-like identifiers that the
preprocessor automatically replaces with the name of the file and the
line number (respectively) in which they appeared. These have been
around forever(?).

They're not just '"macro"-like identifiers'. They're macros.
 
R

Robin Haigh

Martin Jørgensen said:

(all questions agreed)
Let me be sure I understand this:

array[0] = start address of block = 3a4db0
array[1] = array[0] + size of 1 row
array[2] = array[1] + size of 1 row

It that correct or not?
yes
So the debugger shows
array = address of vector = 3a4d58
*array = array[0] = element 0 of vector = start address of row 0 = 3a4db0
**array = array[0][0] = -842150451 = uninitialised int data.

Hmmmmmm. I want to see my 2D-array in the debugger. I now successfully
made a program like this:

count = 0;
for(i=0; i<=nx; i++) /* go through all rows */
{
for(j=0; j<=ny; j++){array[j] = ++count;}
printout(0, nx, 0, ny, array);
}

Calling printout gives me the expected values (all are double values):

1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0
8.0, 9.0, 10, 11, 12, 13, 14
15, 16, 17, 18, 19, 20, 21
22, 23, 24, 25, 26, 27, 28
29, 30, 31, 32, 33, 34, 35
36, 37, 38, 39, 40, 41, 42
43, 44, 45, 46, 47, 48, 49

So it works. I just want to be able to debug just by watching things in
memory. Moving my mouse pointer over array gives me (probably new memory
location compared to yesterday):

1) 0x003a4d60. Clicking the "+"-sign gives me:
2) 0x003a4db8. And clicking the "+"-sign again gives me the first array
element:
3) 1.0!

Hooray... My memory dump looks like this:

0x003A4DB8 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 40 00 00
......?.......@..
0x003A4DCA 00 00 00 00 08 40 00 00 00 00 00 00 10 40 00 00 00 00
.....@.......@....
0x003A4DDC 00 00 14 40 00 00 00 00 00 00 18 40 00 00 00 00 00 00
...@.......@......
...
...

That is double. As wrote earlier: I want see my numbers array 1 to 49? I
don't remember if a double value (double pointer?) takes 8 bytes but if
so, I remember that the first value (00 00 00 00 00 00 f0 3f) must be
something like: 3ff0 or something. Please tell me how to convert these
bytes from the memory dump to a memory location...


These are your doubles that you're looking at. Yes, they are 8 bytes, and
3ff0000000000000 is the internal representation of 1.0 as a double. You
don't have to do anything else to find it -- the trick would be to get it
displayed in a more human-readable display format

My guess is that I should look 0x003a4db8 and find out where it points
to (something with 3ff0 - please tell me, I'm not sure). And looking
*there* I hope to find the first array element: 1.0......?

No, 3a4db8 is the value of array[0], so it's the value of a double*, which
means it's the address of a double. So, when you're looking at the contents
of location 3a4db8, you're looking at the actual double, no more pointers to
follow.


nx and ny was not variables. They were #define'd if that makes any
difference...

It makes all the difference. It means your arrays are fixed size, not
variable, as far as the compiler is concerned. No mallocs required. Going
back to your original code,

void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int array[][])
{
for(i=startx; i<=stopx; i++)
{
for(j=starty; j<=stopy; j++)
{
array[j] = fillvalue;
}
}
}

you can fix that just by changing int array[][] to int array[][ny+1]. That
doesn't work in any kind of C if ny is a variable, but if it's a macro for a
constant, no problem.



This code dumps out the internal representations of some 8-byte doubles:

#include <stdio.h>
char hex[] = "0123456789abcdef";
int main (void) {
int i;
double a;
unsigned char *pc;
pc = (unsigned char *)&a;
for ( i = 0 ; i < 50 ; i++ ) {
a = (double)i;
printf("%5.1f %c%c %c%c %c%c %c%c %c%c %c%c %c%c %c%c\n", a,
hex[pc[0] >> 4], hex[pc[0] & 0xf],
hex[pc[1] >> 4], hex[pc[1] & 0xf],
hex[pc[2] >> 4], hex[pc[2] & 0xf],
hex[pc[3] >> 4], hex[pc[3] & 0xf],
hex[pc[4] >> 4], hex[pc[4] & 0xf],
hex[pc[5] >> 4], hex[pc[5] & 0xf],
hex[pc[6] >> 4], hex[pc[6] & 0xf],
hex[pc[7] >> 4], hex[pc[7] & 0xf]);
}
return 0;
}

output:
0.0 00 00 00 00 00 00 00 00
1.0 00 00 00 00 00 00 f0 3f
2.0 00 00 00 00 00 00 00 40
3.0 00 00 00 00 00 00 08 40
4.0 00 00 00 00 00 00 10 40
5.0 00 00 00 00 00 00 14 40
6.0 00 00 00 00 00 00 18 40
7.0 00 00 00 00 00 00 1c 40
8.0 00 00 00 00 00 00 20 40
9.0 00 00 00 00 00 00 22 40
10.0 00 00 00 00 00 00 24 40
11.0 00 00 00 00 00 00 26 40
12.0 00 00 00 00 00 00 28 40
13.0 00 00 00 00 00 00 2a 40
14.0 00 00 00 00 00 00 2c 40
15.0 00 00 00 00 00 00 2e 40
16.0 00 00 00 00 00 00 30 40
17.0 00 00 00 00 00 00 31 40
18.0 00 00 00 00 00 00 32 40
19.0 00 00 00 00 00 00 33 40
20.0 00 00 00 00 00 00 34 40
21.0 00 00 00 00 00 00 35 40
22.0 00 00 00 00 00 00 36 40
23.0 00 00 00 00 00 00 37 40
24.0 00 00 00 00 00 00 38 40
25.0 00 00 00 00 00 00 39 40
26.0 00 00 00 00 00 00 3a 40
27.0 00 00 00 00 00 00 3b 40
28.0 00 00 00 00 00 00 3c 40
29.0 00 00 00 00 00 00 3d 40
30.0 00 00 00 00 00 00 3e 40
31.0 00 00 00 00 00 00 3f 40
32.0 00 00 00 00 00 00 40 40
33.0 00 00 00 00 00 80 40 40
34.0 00 00 00 00 00 00 41 40
....
 
J

Jordan Abel

Quite, sorry. I was too lazy to check that up.

it's __function__ that has magic associated with it - its use causes a
local variable to have been declared in the top of the current function
scope.
 
K

Keith Thompson

Jordan Abel said:
Keith Thompson said:
[...]
__FILE__ and __LINE__ are special "macro"-like identifiers that the
preprocessor automatically replaces with the name of the file and the
line number (respectively) in which they appeared. These have been
around forever(?).

They're not just '"macro"-like identifiers'. They're macros.

Quite, sorry. I was too lazy to check that up.

it's __function__ that has magic associated with it - its use causes a
local variable to have been declared in the top of the current function
scope.

Actually, it's __func__. <OT>gcc has __FUNCTION__.</OT>
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Robin said:
-snip-



These are your doubles that you're looking at. Yes, they are 8 bytes, and
3ff0000000000000 is the internal representation of 1.0 as a double. You
don't have to do anything else to find it -- the trick would be to get it
displayed in a more human-readable display format

Do you or does anyone in here either know how to make MS visual studio
2005 do the trick or if there exists such a program I can download for
windows xp, so I can put up breakpoints and easily see if the right
values are in a particular location?

Might work well if I for instance just could copy/paste from the memory
dump to the conversion utility...
My guess is that I should look 0x003a4db8 and find out where it points
to (something with 3ff0 - please tell me, I'm not sure). And looking
*there* I hope to find the first array element: 1.0......?


No, 3a4db8 is the value of array[0], so it's the value of a double*, which
means it's the address of a double. So, when you're looking at the contents
of location 3a4db8, you're looking at the actual double, no more pointers to
follow.

Fine, ok.
nx and ny was not variables. They were #define'd if that makes any
difference...


It makes all the difference. It means your arrays are fixed size, not
variable, as far as the compiler is concerned. No mallocs required. Going
back to your original code,

void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int array[][])
{
for(i=startx; i<=stopx; i++)
{
for(j=starty; j<=stopy; j++)
{
array[j] = fillvalue;
}
}
}

you can fix that just by changing int array[][] to int array[][ny+1]. That
doesn't work in any kind of C if ny is a variable, but if it's a macro for a
constant, no problem.


Ok, I'll test that later.
This code dumps out the internal representations of some 8-byte doubles:

#include <stdio.h>
char hex[] = "0123456789abcdef";
int main (void) {
int i;
double a;
unsigned char *pc;
pc = (unsigned char *)&a;
for ( i = 0 ; i < 50 ; i++ ) {
a = (double)i;
printf("%5.1f %c%c %c%c %c%c %c%c %c%c %c%c %c%c %c%c\n", a,
hex[pc[0] >> 4], hex[pc[0] & 0xf],
hex[pc[1] >> 4], hex[pc[1] & 0xf],
hex[pc[2] >> 4], hex[pc[2] & 0xf],
hex[pc[3] >> 4], hex[pc[3] & 0xf],
hex[pc[4] >> 4], hex[pc[4] & 0xf],
hex[pc[5] >> 4], hex[pc[5] & 0xf],
hex[pc[6] >> 4], hex[pc[6] & 0xf],
hex[pc[7] >> 4], hex[pc[7] & 0xf]);
}
return 0;
}

output:
0.0 00 00 00 00 00 00 00 00
1.0 00 00 00 00 00 00 f0 3f
2.0 00 00 00 00 00 00 00 40
3.0 00 00 00 00 00 00 08 40
4.0 00 00 00 00 00 00 10 40
5.0 00 00 00 00 00 00 14 40
6.0 00 00 00 00 00 00 18 40
7.0 00 00 00 00 00 00 1c 40
8.0 00 00 00 00 00 00 20 40
9.0 00 00 00 00 00 00 22 40
10.0 00 00 00 00 00 00 24 40
.....

Nice. Do you also have a code routine for going the other way?


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Robin said:
-snip-

These are your doubles that you're looking at. Yes, they are 8 bytes, and
3ff0000000000000 is the internal representation of 1.0 as a double. You
don't have to do anything else to find it -- the trick would be to get it
displayed in a more human-readable display format

Hmm... I tried this one:

http://babbage.cs.qc.edu/IEEE-754/IEEE-754.html

I don't think it works, does it? It either complaints about entering too
many or too few digits...


Best regards / Med venlig hilsen
Martin Jørgensen
 
C

CBFalconer

Robin said:
.... snip ...

This code dumps out the internal representations of some 8-byte doubles:

#include <stdio.h>
char hex[] = "0123456789abcdef";
int main (void) {
int i;
double a;
unsigned char *pc;
pc = (unsigned char *)&a;
for ( i = 0 ; i < 50 ; i++ ) {
a = (double)i;
printf("%5.1f %c%c %c%c %c%c %c%c %c%c %c%c %c%c %c%c\n", a,
hex[pc[0] >> 4], hex[pc[0] & 0xf],
hex[pc[1] >> 4], hex[pc[1] & 0xf],
hex[pc[2] >> 4], hex[pc[2] & 0xf],
hex[pc[3] >> 4], hex[pc[3] & 0xf],
hex[pc[4] >> 4], hex[pc[4] & 0xf],
hex[pc[5] >> 4], hex[pc[5] & 0xf],
hex[pc[6] >> 4], hex[pc[6] & 0xf],
hex[pc[7] >> 4], hex[pc[7] & 0xf]);
}
return 0;
}
.... snip ...

on machines where a byte is 8 bits, and a double is 8 bytes. The
actual output may vary from what you got. You gotta know your
limitations.

On your machine it would probably make more sense to you if you
reversed the order of output bytes, i.e. dump pc[7] first, down
through pc[0].

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
M

Micah Cowan

Jordan Abel said:
Keith Thompson said:
[...]
__FILE__ and __LINE__ are special "macro"-like identifiers that the
preprocessor automatically replaces with the name of the file and the
line number (respectively) in which they appeared. These have been
around forever(?).

They're not just '"macro"-like identifiers'. They're macros.

Quite, sorry. I was too lazy to check that up.

it's __function__ that has magic associated with it - its use causes a
local variable to have been declared in the top of the current function
scope.

(As someone else reminded, it's __func__...)

Well, technically, AFA the standard is concerned, it's /always/
declared at the beginning of each function definition... it's just
that the "as-if" rule permits this obviously desirable optimization.
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Keith said:
They're not just '"macro"-like identifiers'. They're macros.

Okay... But I would still like an check-if-pointer-in-not-NULL-function
that returns an error if space could not be allocated...

Like:
int **array = malloc((nx+1)*sizeof(int*));
checkPtr_error(something here probably?)

int **var1 = malloc((nx+1)*sizeof(int*));
checkPtr_error(something here probably?)

int **var2 = malloc((nx+1)*sizeof(int*));
checkPtr_error(something here probably?)

int **doubleptr = malloc((nx+1)*sizeof(double*));
checkPtr_error(something here probably?)

etc.

So what would you suggest? Here's my old one (untested still):

checkPtr_error(%s location, %p pointer)
{
if (pointer == NULL)
{
fputs("Memory allocation failure (%s). Bye\n", location, stderr);
}
}


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Robin said:
-snip-
My guess is that I should look 0x003a4db8 and find out where it points
to (something with 3ff0 - please tell me, I'm not sure). And looking
*there* I hope to find the first array element: 1.0......?


No, 3a4db8 is the value of array[0], so it's the value of a double*, which
means it's the address of a double. So, when you're looking at the contents
of location 3a4db8, you're looking at the actual double, no more pointers to
follow.

Thanks! It seems to work now... I found out that if I right-clich I can
choose float 64 bits (or something) and then the debugger automatically
writes the values in double... Very nice.

Also, I found out I can just write 3a4db8 + 16*8 to move to index[16].
And the 16*8 is not even hexagonal - it's ordinary (10-base) decimal, so
it's really nice to use once I learned it :)
It makes all the difference. It means your arrays are fixed size, not
variable, as far as the compiler is concerned. No mallocs required. Going
back to your original code,

I thought so...
void fillinnumbers(int fillvalue, int startx, int stopx, int starty, int
stopy, int array[][])
{
for(i=startx; i<=stopx; i++)
{
for(j=starty; j<=stopy; j++)
{
array[j] = fillvalue;
}
}
}

you can fix that just by changing int array[][] to int array[][ny+1]. That
doesn't work in any kind of C if ny is a variable, but if it's a macro for a
constant, no problem.

-snip-

Thanks again... I feel much "wiser" now :)


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Michael Mair

Martin said:
Okay... But I would still like an check-if-pointer-in-not-NULL-function
that returns an error if space could not be allocated...

Like:
int **array = malloc((nx+1)*sizeof(int*));

Make that
int **array = malloc((nx + 1) * sizeof *array);
checkPtr_error(something here probably?)
int **doubleptr = malloc((nx+1)*sizeof(double*));

This here proves it nicely: if sizeof (double *) != sizeof (int *),
you may be in for a long bug hunt.
Once more
T **doubleptr = malloc((nx + 1) * sizeof *doubleptr);
is always correct irrespective of the actual type T represents.
checkPtr_error(something here probably?)

etc.

So what would you suggest? Here's my old one (untested still):

checkPtr_error(%s location, %p pointer)
{
if (pointer == NULL)
{
fputs("Memory allocation failure (%s). Bye\n", location, stderr);
}
}

*sigh* Please provide something that compiles.

You probably meant
void checkPtr_error(const char *location, const void *pointer)
{
if (pointer == NULL) {
fprintf(stderr, "Memory allocation failure (%s). Bye\n",
location ? location : "Unknown location");
exit(EXIT_FAILURE);
}
}

As pointed out elsethread:
- This does not take care of the already allocated memory,
open files and other resources.
- Generating a helpful, ideally unique location string to
facilitate debugging may be complex so that the generation
of the location string should ideally take place within
the if (pointer == NULL) case, i.e. outside of
checkPtr_error
- You do not gain anything substantial by using this function
instead of some kind of dedicated debug/error output function.


Cheers
Michael
 
K

Keith Thompson

Martin Jørgensen said:
Okay... But I would still like an check-if-pointer-in-not-NULL-function
that returns an error if space could not be allocated... [snip]
So what would you suggest? Here's my old one (untested still):

checkPtr_error(%s location, %p pointer)
{
if (pointer == NULL)
{
fputs("Memory allocation failure (%s). Bye\n", location, stderr);
}
}

No offense, but is that supposed to be C?

"%s" and "%p" are printf format specifiers, not something to be used
in a function declaration. fputs() doesn't take a format string; you
give it a "%s", which is just the characters '%' and 's' as far as
it's concerned. And if pointer is null, you print an error message,
but you continue executing with the bad value.

Perhaps you're looking for something like this:
================================
#include <stdio.h>
#include <stdlib.h>

void *checked_malloc(size_t size, char *file, int line)
{
void *result = malloc(size);
if (result == NULL) {
fprintf(stderr, "%s:%d malloc(%ld) failed\n", file, line, size);
exit(EXIT_FAILURE);
}
fprintf(stderr, "%s:%d malloc(%ld) ok\n", file, line, size);
return result;
}

#define CHECKED_MALLOC(size) checked_malloc(size, __FILE__, __LINE__);

int main(void)
{
void *ptr = CHECKED_MALLOC(100);
printf("ptr = %p\n", ptr);
return 0;
}
================================

The error handling is primitive; it simply aborts the program if
memory could not be allocated. Very likely there's not much more
you're going to be able to do, but in practice you might want to do
some cleanup; consider using atexit() to invoke any cleanup routines.
The "malloc ... ok" message shows you what the messages look like; you
won't want it in production code.
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael Mair wrote:
-snip-
This here proves it nicely: if sizeof (double *) != sizeof (int *),
you may be in for a long bug hunt.
Ok.

-snip-

As pointed out elsethread:
- This does not take care of the already allocated memory,
open files and other resources.

My mallocs happens in the beginning of the program so no files or other
resources are opened at this point. The already allocated memory is
free'd when the program closes and if it can't get the memory it needs,
then it can't do anything about that at all and therefore I don't see
any problem with this method.
- Generating a helpful, ideally unique location string to
facilitate debugging may be complex so that the generation
of the location string should ideally take place within
the if (pointer == NULL) case, i.e. outside of
checkPtr_error
- You do not gain anything substantial by using this function
instead of some kind of dedicated debug/error output function.

I don't understand that viewpoint. I gain that substantial effect, that
I don't overwrite anything in memory because the program shuts itself
down before it tries to do anything stupid. Moreover, I get to know
exactly which malloc caused the error so I can see if I made any errors
at that point.


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Keith said:
No offense, but is that supposed to be C?

No, that was some quick pseudo-/semi-C code. I didn't knew that was a
problem, because next time I could perhaps quickly just as well check it
through my compiler if that is a big problem. I just wanted to save some
time.
"%s" and "%p" are printf format specifiers, not something to be used
in a function declaration. fputs() doesn't take a format string; you
give it a "%s", which is just the characters '%' and 's' as far as
it's concerned. And if pointer is null, you print an error message,
but you continue executing with the bad value.

Well, I'm not a C-expert. Just began to learn it recently and I
know/knew that those are printf specifiers and not correctly used.
Perhaps you're looking for something like this:
================================
#include <stdio.h>
#include <stdlib.h>

void *checked_malloc(size_t size, char *file, int line)
{
void *result = malloc(size);
if (result == NULL) {
fprintf(stderr, "%s:%d malloc(%ld) failed\n", file, line, size);
exit(EXIT_FAILURE);
}
fprintf(stderr, "%s:%d malloc(%ld) ok\n", file, line, size);
return result;
}

#define CHECKED_MALLOC(size) checked_malloc(size, __FILE__, __LINE__);

int main(void)
{
void *ptr = CHECKED_MALLOC(100);
printf("ptr = %p\n", ptr);
return 0;
}
================================

The error handling is primitive; it simply aborts the program if
memory could not be allocated. Very likely there's not much more

That's fine enough for me. No data lost. In fact I like that code very
much...
you're going to be able to do, but in practice you might want to do
some cleanup; consider using atexit() to invoke any cleanup routines.
The "malloc ... ok" message shows you what the messages look like; you
won't want it in production code.

Got that... I also looked at atexit() from my C-book and there was a
nice example. I get the point. Thanks a lot for those comments... I
appreciate them.


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Michael Mair

Martin said:
Michael Mair wrote:
[context: Using
void checkPtr_error(const char *location, const void *pointer)
{
if (pointer == NULL) {
fprintf(stderr, "Memory allocation failure (%s). Bye\n",
location ? location : "Unknown location");
exit(EXIT_FAILURE);
}
}
]
My mallocs happens in the beginning of the program so no files or other
resources are opened at this point. The already allocated memory is
free'd when the program closes and if it can't get the memory it needs,
then it can't do anything about that at all and therefore I don't see
any problem with this method.

Do you handle the "already allocated memory" with atexit() to
be on the safe side? If you do: Yes, that takes care of it.
Otherwise, you are only _hoping_ that it is taken care of.

In your scenario (malloc() first) this may suffice.

However, you may find yourself calling the respective function
recursively or whatever -- if you then change your error
handling to returning an error in a less disruptive manner,
then you may still bind memory other processes might have
used. Or your programme becomes one or several library
functions and you can no longer die "just like that", then
returning an error but forgetting to free the memory may eat
up the storage slowly.

Apart from that: If you leave out calls to free() in the above
scenario, you may be tempted to leave them out in principle.
However, the programme-becomes-library thing applies much more
in this case; in addition, in my experience free()ing helps
find more errors than checking whether malloc() returned a
null pointer -- often writing over the boundaries of the
allocated storage makes itself felt when calling free().

As long as your operating system or implementation does not
_guarantee_ you that allocated storage is taken care of as if
you had free()d it explicitly, I'd rather explicitly free()
the storage.
I don't understand that viewpoint. I gain that substantial effect, that
I don't overwrite anything in memory because the program shuts itself
down before it tries to do anything stupid. Moreover, I get to know
exactly which malloc caused the error so I can see if I made any errors
at that point.

If you malloc() all the memory essentially at once, the information
is not as valuable as you may think.
In this case you can as well go for
a = malloc(asize * sizeof *a);
...
foo = malloc(foosize * sizeof *foo);
if (!(a && ... && foo)) {
/* you can still find out the pointer where it first went wrong */
/* handle error */
}
without loosing anything. In fact, calling your checkPtr_error()
inside the fail branch for all returned pointers is perfectly
acceptable in my book as there is only a slight waste of time
in case of failure.

Keep the null pointer checks together with the malloc()s; see
Keith's CHECKED_MALLOC from <[email protected]> which
does the same job as your suggestion with only one function/macro
call and keeps the checks together.

Cheers
Michael


PS: As a macro is used anyway, I'd consider going all the way:

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

/* belongs to some kind of "debug.c" */
#include <stdarg.h>

int DebugErrPrintf(const char *format, ...)
{
int ret;
va_list arglist;
va_start(arglist, format);
ret = vfprintf(stderr, format, arglist);
va_end(arglist);
return ret;
}

int DebugTracePrintf(const char *format, ...)
{
return 0;
}
/* end "debug.c" */

void *checked_malloc(size_t size,
const char *optInfo)
{
void *result = malloc(size);
if (result == NULL) {
DebugErrPrintf("%s malloc(%lu) failed\n",
optInfo ? optInfo : "", (unsigned long)size);
exit(EXIT_FAILURE);
}
DebugTracePrintf("%s malloc(%lu) ok\n",
optInfo ? optInfo : "", (unsigned long)size);
return result;
}

#define STRINGIZE(s) #s
#define XSTR(s) STRINGIZE(s)
#define CHECKED_BYTENO_MALLOC(dest, size) \
((dest) = checked_malloc((size), \
#dest ":" \
__FILE__ ":" \
XSTR(__LINE__) \
))
#define CHECKED_ARRAY_MALLOC(dest, size) \
CHECKED_BYTENO_MALLOC(dest, (size) * sizeof *(dest))

int main(void)
{
double *dptr;
void *vptr;

CHECKED_ARRAY_MALLOC(dptr, 42);
printf("dptr = %p\n", (void *)dptr);
free(dptr);

CHECKED_BYTENO_MALLOC(vptr, (size_t)-2);
printf("vptr = %p\n", vptr);
free(vptr);

return 0;
}
 

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,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top