Returning int pointer ?

M

Mahendra

I have following code snippet -

int *createIncidenceMatrix(int numEdges, int numVertices) {
int *p = (int *) calloc((numEdges*numVertices), sizeof(int));
if(p == NULL) {
printf("Could not allocate memory");
exit(0);
}
return p;
}


void createIncidencePerView(int numEdges, int numVertices, int viewId) {
int *pnew = createIncidenceMatrix(numEdges, numVertices);
}

This code compiles fine. I am trying to understand if this will run as
intended. Obviously, I tried running the code also. My question is -

When createIncidenceMatrix() return p which is local variable, will p
get deallocated at return call ?

So when i make createIncidenceMatrix() call inside
createIncidencePerView(), will the call createIncidenceMatrix() tries to
assign deallocated local pointer to the pnew pointer ?

Thanks
Mahendra
 
B

Bartc

Mahendra said:
I have following code snippet -

int *createIncidenceMatrix(int numEdges, int numVertices) {
int *p = (int *) calloc((numEdges*numVertices), sizeof(int));
if(p == NULL) {
printf("Could not allocate memory");
exit(0);
}
return p;
}


void createIncidencePerView(int numEdges, int numVertices, int viewId) {
int *pnew = createIncidenceMatrix(numEdges, numVertices);
}

This code compiles fine. I am trying to understand if this will run as
intended. Obviously, I tried running the code also. My question is -

When createIncidenceMatrix() return p which is local variable, will p
get deallocated at return call ?

p is a pointer (to the memory you've allocated). The few bytes it takes up
/will/ be deallocated on return, but not before a copy of those bytes (the
value of the pointer variable p) has been made to return from the function.
 
A

Andrey Tarasevich

Mahendra said:
I have following code snippet -

int *createIncidenceMatrix(int numEdges, int numVertices) {
int *p = (int *) calloc((numEdges*numVertices), sizeof(int));

Don't cast the results of memory allocation functions.

int *p = calloc((numEdges*numVertices), sizeof(int));

Also, personally I'd do it as follows

int *p = calloc(numEdges * numVertices, sizeof *p);
if(p == NULL) {
printf("Could not allocate memory");
exit(0);
}
return p;
}


void createIncidencePerView(int numEdges, int numVertices, int viewId) {
int *pnew = createIncidenceMatrix(numEdges, numVertices);
}

This code compiles fine. I am trying to understand if this will run as
intended. Obviously, I tried running the code also. My question is -

When createIncidenceMatrix() return p which is local variable, will p
get deallocated at return call ?

It depends on what you mean by "deallocated".

'p' itself is a local variable in 'createIncidenceMatrix'. It will be
destroyed as 'createIncidenceMatrix' exit. So, yes 'p' itself does get
"deallocated".

But the memory block you allocated by the 'calloc' call (and whose
address you stored in 'p') _never_ gets deallocated automatically.
Everything you allocate manually (by 'calloc', 'malloc' etc.) lives
forever, or until you _manually_ deallocate it (with 'free' etc.).

So, as 'createIncidenceMatrix' exits, the pointer 'p' itself disappears,
but the block you allocated by 'calloc' persists. In order to keep track
of that memory block (avoid it becoming a memory leak), you have to
memorize its address (the value of 'p') somewhere else. The above code
does exactly that. The 'return' statement will make sure that the value
of 'p' is safely makes it to 'pnew' in 'createIncidencePerView'. That's
how 'return' works in C.
So when i make createIncidenceMatrix() call inside
createIncidencePerView(), will the call createIncidenceMatrix() tries to
assign deallocated local pointer to the pnew pointer ?

No. Inside 'createIncidencePerView' you assign the preserved value of
now-dead local pointer 'p' to another local pointer 'pnew'. All the time
the value in question points to a persistent block of dynamic memory
(allocated with 'calloc'), which will persist until you manually
deallocate it.
 
M

Mahendra

Bartc said:
p is a pointer (to the memory you've allocated). The few bytes it takes
up /will/ be deallocated on return, but not before a copy of those bytes
(the value of the pointer variable p) has been made to return from the
function.
Will it copy the bytes - holding pointer variable or copy the bytes
holding the value of pointer variable ?

If it does the latter as described by you, where is this memory
allocated - heap ? Does this mean "return" call creates heap memory copy ?

Thanks
Mahendra
 
S

s0suk3

Don't cast the results of memory allocation functions.

Why specifically memory allocation functions? That argument would
apply to any function that returns a void *. For example, you wouldn't
want to cast a memcpy() call either, simply because it's not
necessary. However, you're probably just saying it because of
comp.lang.c's old myth that malloc() shouldn't be cast (for whatever
reason).

Sebastian
 
S

s0suk3

(e-mail address removed) said:

Hardly a myth. More like common sense.

Well, lack of common sense isn't the reason people cast these
functions. AFAIK, there are three reasons: (1) It was required in
versions prior to C89 (I hear malloc() & friends used to return char
*), (2) it's shown that way in K&R2, and (3), it's required in C++
(stronger type checking). (2) is probably the main reason why so many
people still do this (K&R2 is still the primary C textbook). (1) is
probably less relevant nowadays. And (3) is the only justified one (in
case you need to write code that compiles as both C and C++).

Anyway, I think the whole argument against this cast is mostly style
flaming.

Sebastian
 
H

Harald van Dijk

Well, lack of common sense isn't the reason people cast these
functions. AFAIK, there are three reasons: [...]
and (3), it's required in C++
(stronger type checking).

The only thing I disagree with here is the parenthetical statement
"stronger type checking". I would replace that with the phrase "lack of
void * type".

But then it's simply untrue, because C++ does have a void * type.
 
P

Peter Nilsson

Richard Heathfield said:
Malcolm McLean said:

In the same way that C90 programmers are vanishingly small,
but there's still _LOTS_ of them.

It may be more accurate to say you never gave the reasons
more than ten seconds scrutiny until they where the ones
saying it.

To my knowledge, neither of them have asked you to be
convinced. The irony for me is that Ian's reasons are the
least convincing I've heard. Of course, I don't have to be
convinced by them. I just understand them.
It's more useful to compile your C functions with a
C compiler, put them into a C library, and link them to
your C++ program in the canonical way.

What is the canonical way? The C++ standard doesn't state
you can link any and all C object files. That's one of the
reasons why many decided to hang the sense of it and make
their C code compilable as C++.

Plauger went to far as to have the linkage of the C
standard library implementation defined, precisely so he
(and other implementors) could have their C standard
library compilable as C++.
 
I

Ian Collins

Richard said:
Peter Nilsson said:


I *think* I understand Ian's reason. To me, it flies in the face of good
testing practice, however, so personally I'm not convinced - but it was
the first reason I've ever heard of (apart from Plauger's) that wasn't one
I'd already considered and rejected.
One has to differentiate between simulation and testing.

I tend to work with complex real-time systems with many components, each
with its own software. One example being DC power systems. The system
comprises rectifiers with their control software and the system
controllers with their software.

The rectifier designers like to model the rectifier's control circuits
and the software bods like to verify the *dynamic* behaviour of the
control software, often before the hardware is available. Even with
real hardware, very loud and smelly things can happen if the software
and hardware don't get along.

The system designers like to model the *dynamic* behaviour of the system
as governed by the controller software.

So we have layers of simulations at each stage.

Being able to simulate hardware before it is built reduces the all
important time to market.
 
C

CBFalconer

Malcolm said:
.... snip ...

Finally terrible news comes in. We've implemented writeasciiz as

int writeasciiz(char *str, FILE *fp) {
while (*str)
fputc(*str++, fp);
fputc(0, fp);
return ferror(fp) ? EOF : 0;
}

Of course this won't cut the mustard when we move to a non-ascii
machine.

Why not? The only dependency is on '\0' being a string end marker.
 
K

Keith Thompson

Richard Heathfield said:
CBFalconer said:

Because on a non-ASCII machine, it won't write ASCII. It will write the
native character set.

It will write whatever you ask it to write.
For example, on a typical IBM mainframe using
EBCDIC, if you call it thusly:

writeasciiz("Hello", stdout);

instead of getting the required output - byte values 72, 101, 108, 108,
111, and 0 - written to the stream, you'll get 200, 133, 147, 147, 150,
and 0.

And if you call it thusly:

char hello[] = { 72, 101, 108, 108, 111, 0);
writeasciiz(hello, stdout);

it will write "Hello" in ASCII.
The function writes, not ASCII, but native. If native is ASCII, great. But
if native is non-ASCII, then the function doesn't do what it says on the
tin.

It writes native only if you ask it to write native.

I admit that, given the name, confusion is likely.

[...]
 
P

Phil Carmody

Richard Heathfield said:
CBFalconer said:

Because on a non-ASCII machine, it won't write ASCII.

How do we know that the string pointed to by str isn't an ASCII
string? We don't know the interface, we only know the implementation.
The function name is just ambiguous enough for some doubt to be
raised.

Phil
 
B

Ben Bacarisse

Malcolm McLean said:
"Keith Thompson" <[email protected]> wrote in message
And if you call it thusly:

char hello[] = { 72, 101, 108, 108, 111, 0);
writeasciiz(hello, stdout);

it will write "Hello" in ASCII.
I tried it and it worked, so I thought, let's try adding a star

char hello_star[] = { 72, 101, 108, 108, 111, 42, 0 };

and it crashed out. What on Earth could have happened? (This was the
DS9000)

How odd. On my DS9000 the execution character set is such that all
signed char values < 256 (zero excepted) are trap representations and,
of course, plain char is signed. You must be using the /bekindtome
compiler option.
 
P

Phil Carmody

Malcolm McLean said:
You assume that a char holds a character in the execution character
set. If it doesn't you theoretically risk trap representations.

I thought character types were specifically excluded from trap
representations?
unsigned char is for bytes, signed char for tiny integers. It's just
unfortunate historical baggage that C doesn't have a "byte" type.

Very unfortunate. More so that 'char' doesn't really know what it is.

Phil
 
B

Ben Bacarisse

Malcolm McLean said:
unsigned char is, signed char not.
However signed char is guaranteed 8 bits, so in fact it can hold ASCII
codes. Plain char must be an alias for either signed char or unsigned
char. So Keith Thompson actually squeaks through.

So why can't some (or most) ASCII values be trap representations (as I
suggested in a previous reply)? If you say "it would be daft" I'll
agree, but I thought you were talking about what is theoretically
permitted.
 
K

Keith Thompson

Ben Bacarisse said:
Malcolm McLean said:
"Keith Thompson" <[email protected]> wrote in message
And if you call it thusly:

char hello[] = { 72, 101, 108, 108, 111, 0);
writeasciiz(hello, stdout);

it will write "Hello" in ASCII.
I tried it and it worked, so I thought, let's try adding a star

char hello_star[] = { 72, 101, 108, 108, 111, 42, 0 };

and it crashed out. What on Earth could have happened? (This was the
DS9000)

How odd. On my DS9000 the execution character set is such that all
signed char values < 256 (zero excepted) are trap representations and,
of course, plain char is signed. You must be using the /bekindtome
compiler option.

No signed char values within the range 0 .. SCHAR_MAX can be trap
representations; they're not representations, they're values.

I suppose Malcolm's version of the program could crash if the file is
opened in text mode. If it's opened in binary mode, I don't see how
it could crash.
 
K

Keith Thompson

Ben Bacarisse said:
So why can't some (or most) ASCII values be trap representations (as I
suggested in a previous reply)? If you say "it would be daft" I'll
agree, but I thought you were talking about what is theoretically
permitted.

Because no value can be a trap representation.
 
K

Keith Thompson

Malcolm McLean said:
putasciiz() is inherently a binary mode function.

I'll assume you're referring to the writeasciiz function that you
introduced upthread.
You'd just get a
mess on the screen if you passed stdout,

stdout is not the only text stream, and text streams aren't always
displayed on screens.
unless by some strange
coincidence your computer uses the same encoding.
Given 126 values in a signed 8-bit char,

Don't you mean 127?
and 26*2 letters and 10
digits, plus the minus sign and space, that's 54,

What exactly is your basis for considering only those characters? Why
exclude '+', for example?
I make that a 1 in
126!/ 72! or 1 in 3.87 * 10^107 chance that putasciiz() will work in
text mode on your particular machine.

And you seem to be assuming that character sets are chosen randomly
and with equal probability.

I'm at a loss to understand what point you're making. Perhaps it
would help if you told us just what your writeasciiz function is
supposed to do. You've just shown us a declaration, leaving us no
basis for determining whether it will "work" on *any* system.
 
P

Phil Carmody

Malcolm McLean said:
unsigned char is, signed char not.

Is that so?

"""
Certain object representations need not represent a value of the object type. If the stored
value of an object has such a representation and is read by an lvalue expression that does
not have character type, the behavior is undefined. If such a representation is produced
by a side effect that modifies all or any part of the object by an lvalue expression that
does not have character type, the behavior is undefined.41) Such a representation is called
a trap representation.
"""

which follows:
"""
The three types char, signed char, and unsigned char are collectively called
the character types. The implementation shall define char to have the same range,
representation, and behavior as either signed char or unsigned char.35)
"""

I'm not seeing a distinction between unsigned char and signed char
when it comes to trap representations.

That's 1256, by the way - do you have another reference, or a
paragraph within 1256 which says something different?

However signed char is guaranteed 8 bits, so in fact it can hold ASCII
codes. Plain char must be an alias for either signed char or unsigned
char. So Keith Thompson actually squeaks through.

I didn't hear anything.

Phil
 

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
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top