Newbie needs help with pointers/memory allocation

M

Me Alone

Hello list:

I am working on a C assignment. I am to declare a (pointer to pointer
to int), allocate memory for pointer and data, and print some output.

Problem (I think): The memory addresses printed don't look right. Would
any one be so kind to take a look at my code and explain why are the
addresses for the lists printed in "less than optimal" sequence?

Thanks in advance,
Ron

##########################################

#include <stdio.h>

#define T1 2
#define T2 5

main()
{
int i, j, **ptr;

if ((ptr = (int**)malloc(T1 * sizeof(int*))) == NULL)
{
error("Error encountered, will exit now.");
exit(0);
}

if ((*ptr = (int*)malloc(T1 * T2 * sizeof(int))) == NULL)
{
error("Error encountered, will exit now.");
exit(0);
}

for(i=0;i<T1;i++)
{
printf("\nData in table (%d).\n", i);
printf("**ptr addr\t*ptr addr\tvalue\n");
printf("=====================================\n");
for(j=0;j<T2;j++)
{
if(i > 0)
{
*(ptr+i+j) = j + T2;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, (ptr+i+j));
} else {
*(ptr+i+j) = j;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, *(ptr+i+j));
}
}
}
printf("\n");
}


// Output of program
Data in table (0).
**ptr addr *ptr addr value
=====================================
BFF06C84 BFF06C84 0
BFF06C84 BFF06C88 1
BFF06C84 BFF06C8C 2
BFF06C84 BFF06C90 3
BFF06C84 BFF06C94 4

Data in table (1).
**ptr addr *ptr addr value
=====================================
BFF06C88 BFF06C88 5
BFF06C88 BFF06C8C 6
BFF06C88 BFF06C90 7
BFF06C88 BFF06C94 8
BFF06C88 BFF06C98 9
 
F

Frederick Gotham

Me Alone posted:
Hello list:

I am working on a C assignment. I am to declare a (pointer to pointer
to int), allocate memory for pointer and data, and print some output.


The following might get you going:

#include <stdio.h>

#define AL(arr) (sizeof(arr)/sizeof*(arr))

int main(void)
{
int const iarr[] = {0,1,2,3,4,5,6,7,8,9};

int const *const parr[] = {iarr,iarr+1,iarr+2,iarr+3,iarr+4,
iarr+5,iarr+6,iarr+7,iarr+8,iarr+9};

int const *const *p = parr;

int const *const *const p_over = parr + AL(parr);

do
{
printf("%d",**p++);
} while(p != p_over);

return 0;
}

#include <stdio.h>


You'l also want:

#include <stdlib.h>

#define T1 2
#define T2 5

main()


Change that to:

int main(void)

{
int i, j, **ptr;

if ((ptr = (int**)malloc(T1 * sizeof(int*))) == NULL)


Don't cast the return value of "malloc" -- it makes you look like a novice.

Try this:

if( !(ptr = malloc(T1 * sizeof*ptr)) )

{
error("Error encountered, will exit now.");
exit(0);
}

if ((*ptr = (int*)malloc(T1 * T2 * sizeof(int))) == NULL)


Again, don't cast the return value of malloc.

if( !(*ptr = malloc(T1 * T2 * sizeof**ptr)) )

Sorry, I'd examine the rest of your code, but my brain's taken enough
screen-staring for today.
 
B

Barry Schwarz

Hello list:

I am working on a C assignment. I am to declare a (pointer to pointer
to int), allocate memory for pointer and data, and print some output.

Problem (I think): The memory addresses printed don't look right. Would
any one be so kind to take a look at my code and explain why are the
addresses for the lists printed in "less than optimal" sequence?

Thanks in advance,
Ron

##########################################

#include <stdio.h>

You need stdlib.h for malloc.
#define T1 2
#define T2 5

main()
{
int i, j, **ptr;

if ((ptr = (int**)malloc(T1 * sizeof(int*))) == NULL)

Don't cast the return from malloc. It never helps but can cause the
compiler to suppress a diagnostic you would really like to see. And
your code does have the error which the compiler would catch.

ptr points to an uninitialized array of 2 int*.
{
error("Error encountered, will exit now.");

There is no error function defined.
exit(0);
}

if ((*ptr = (int*)malloc(T1 * T2 * sizeof(int))) == NULL)

*ptr (which is the same as ptr[0]) points to an array of 10 int.
{
error("Error encountered, will exit now.");
exit(0);
}

for(i=0;i<T1;i++)
{
printf("\nData in table (%d).\n", i);
printf("**ptr addr\t*ptr addr\tvalue\n");
printf("=====================================\n");
for(j=0;j<T2;j++)
{
if(i > 0)
{
*(ptr+i+j) = j + T2;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, (ptr+i+j));

& has higher precedence than +. This evaluates as (&ptr)+i. Since
ptr has type int**, &ptr has type int***. So does the sum. I'm
pretty sure this is not what you wanted. When i+j > 1, the expression
&ptr+i+j is not a valid value.

If you want to print addresses using printf, you should use %p and
cast the value to void*.
} else {
*(ptr+i+j) = j;

*(ptr+i+j) is the same as ptr[i+j]. Since ptr is an int**, ptr[i+j]
is an int*. j is an int. You cannot assign an int to an int* without
a cast (and in this program you don't even want to). Did your
compiler not generate a diagnostic here? If not, you need to up the
warning level so it does.
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, *(ptr+i+j));
}
}
}
printf("\n");
}


// Output of program

Why did you execute a program that does not compile cleanly?
Data in table (0).
**ptr addr *ptr addr value
=====================================
BFF06C84 BFF06C84 0
BFF06C84 BFF06C88 1
BFF06C84 BFF06C8C 2
BFF06C84 BFF06C90 3
BFF06C84 BFF06C94 4

Data in table (1).
**ptr addr *ptr addr value
=====================================
BFF06C88 BFF06C88 5
BFF06C88 BFF06C8C 6
BFF06C88 BFF06C90 7
BFF06C88 BFF06C94 8
BFF06C88 BFF06C98 9


Remove del for email
 
A

Andrew Poelstra

Hello list:

I am working on a C assignment. I am to declare a (pointer to pointer
to int), allocate memory for pointer and data, and print some output.

Problem (I think): The memory addresses printed don't look right. Would
any one be so kind to take a look at my code and explain why are the
addresses for the lists printed in "less than optimal" sequence?

Thanks in advance,
Ron

##########################################

#include <stdio.h>

#define T1 2
#define T2 5

Magic numbers are almost better than these unmeaningful macros. You
should have better names.

int main (void) is the preferred style, and one that will work with C99.
{
int i, j, **ptr;

Don't declare pointers and non-pointers on the same line; they're
different types. This is legal, but poor style.
if ((ptr = (int**)malloc(T1 * sizeof(int*))) == NULL)

1) There's no reason to have an assignment in an if statement; move it
to the line above for more readability. (This isn't too important for
such a short line.)
2) Don't cast the result of malloc(). It hides the fact that you didn't
include <stdlib.h> and causes undefined behavior.
3) Don't use sizeof on a type. It's almost never what you want to do.

ptr = malloc (T1 * sizeof *ptr);
if (ptr == NULL)
...
{
error("Error encountered, will exit now.");

1) error() is not a standard function. We at clc have no idea what it does.
2) This error message is thoroughly useless; describe the problem.

exit (EXIT_FAILURE); would be better.
}

if ((*ptr = (int*)malloc(T1 * T2 * sizeof(int))) == NULL)
{
error("Error encountered, will exit now.");
exit(0);
}

Ditto.

for(i=0;i<T1;i++)
{
printf("\nData in table (%d).\n", i);
printf("**ptr addr\t*ptr addr\tvalue\n");
printf("=====================================\n");
for(j=0;j<T2;j++)
{
if(i > 0)
{
*(ptr+i+j) = j + T2;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, (ptr+i+j));
} else {
*(ptr+i+j) = j;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, *(ptr+i+j));
}
}
}
printf("\n");
}

To print the value of a pointer, use %p and cast to void*:
printf ("Value of my pointer: %p\n", (void *) ptr);
// Output of program
[Demons extracted from nose and are forced to ride a purple donkey.]
[Or maybe not. Anything can happen with Undefined Behavior.]
 
H

Herbert Rosenau

Hello list:

I am working on a C assignment. I am to declare a (pointer to pointer
to int), allocate memory for pointer and data, and print some output.

Problem (I think): The memory addresses printed don't look right. Would
any one be so kind to take a look at my code and explain why are the
addresses for the lists printed in "less than optimal" sequence?

Thanks in advance,
Ron

##########################################

#include <stdio.h>

#define T1 2
#define T2 5

main()

Has to be
int main(void)
since more than 16 years now.
{
int i, j, **ptr;

if ((ptr = (int**)malloc(T1 * sizeof(int*))) == NULL)

Casting the result of malloc ends up in undefined behaviuor in special
when one forgets to include stdlib.h. And even when you includes
stdlib.h it is a faiture to cast.

In C there is already never a need to cast a pointer to void. Only a
dumbass who knows not what he does is able to cast a pointer to void
to anything else or cast a pointer to any datatype to a pointer to
void.

A programmer who knows what he is doing will avoid any cast only
because the compiler gives a diagnostic as he knows that the
diagnostic shows an error he'd made and the error is NOT becaue he'd
forgotten to cast.
{
error("Error encountered, will exit now.");
exit(0);
}

if ((*ptr = (int*)malloc(T1 * T2 * sizeof(int))) == NULL)

The same as above.
{
error("Error encountered, will exit now.");
exit(0);
}

for(i=0;i<T1;i++)
{
printf("\nData in table (%d).\n", i);
printf("**ptr addr\t*ptr addr\tvalue\n");
printf("=====================================\n");
for(j=0;j<T2;j++)
{
if(i > 0)
{
*(ptr+i+j) = j + T2;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, (ptr+i+j));
} else {
*(ptr+i+j) = j;
printf("%X\t%X\t%d\n", &ptr+i, &ptr+i+j, *(ptr+i+j));
}
}
}
printf("\n");
}


// Output of program
Data in table (0).
**ptr addr *ptr addr value
=====================================
BFF06C84 BFF06C84 0
BFF06C84 BFF06C88 1
BFF06C84 BFF06C8C 2
BFF06C84 BFF06C90 3
BFF06C84 BFF06C94 4

Data in table (1).
**ptr addr *ptr addr value
=====================================
BFF06C88 BFF06C88 5
BFF06C88 BFF06C8C 6
BFF06C88 BFF06C90 7
BFF06C88 BFF06C94 8
BFF06C88 BFF06C98 9

Repair your program by removing the casts and the real cause the
compiler complains.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Herbert said:
Has to be
int main(void)
since more than 16 years now.

In C89, main() is valid. It declares main() as returning int and taking no
parameters. The lack of a prototype only affects how and when diagnostics
are generated for invalid recursive calls to main(), and the lack of an
explicit return type is at worst bad style.
Casting the result of malloc ends up in undefined behaviuor in special
when one forgets to include stdlib.h.

Thanks for at least clarifying this now, but there's still one minor thing.
The behaviour is well-defined if malloc() is called with a proper
declaration in scope. This can happen with or without including <stdlib.h>:

#include <stddef.h>

extern void *malloc(size_t);
extern void free(void *);

int main(void) {
free(malloc(1)); /* no undefined behaviour */
free((char *) malloc(1)); /* still no undefined behaviour */
return 0;
}
And even when you includes
stdlib.h it is a faiture to cast.

Rather, it's considered bad style in most cases.
In C there is already never a need to cast a pointer to void. Only a
dumbass who knows not what he does is able to cast a pointer to void
to anything else or cast a pointer to any datatype to a pointer to
void.

You never answered how you would store a pointer value in an object of type
intptr_t or uintptr_t. Or do only dumbasses do that? Do real programmers
use intptr_t to store currency values, perhaps?
A programmer who knows what he is doing will avoid any cast only
because the compiler gives a diagnostic as he knows that the
diagnostic shows an error he'd made and the error is NOT becaue he'd
forgotten to cast.

Here you go again with your overly broad claims. "Any" cast? Do you want to
clarify that?
 
K

Keith Thompson

Herbert Rosenau said:
Has to be
int main(void)
since more than 16 years now.

That's incorrect. In C90, "main()" is perfectly legal, and if I
recall correctly you'll find multiple instances of it in examples in
K&R2. C99 removed implicit int from the language, making "main()" a
constraint violation, but few compilers enforce this unless they're
specifically invoked in a strict C99-conforming mode.

"int main(void)" is better than "main()", and it has been since the
ANSI standard was introduced in 1989, but there's no need to overstate
the case.
Casting the result of malloc ends up in undefined behaviuor in special
when one forgets to include stdlib.h. And even when you includes
stdlib.h it is a faiture to cast.

Didn't we just go over this?

No, casting the result of malloc() does not invoke undefined behavior.
If there's no visible prototype for malloc() (the way to get one is
"#include <stdlib.h>"), then just *calling* malloc() invokes undefined
behavior, regardless of what you do with the result.

See the FAQ for more information.
In C there is already never a need to cast a pointer to void. Only a
dumbass who knows not what he does is able to cast a pointer to void
to anything else or cast a pointer to any datatype to a pointer to
void.

I haven't found that calling people "dumbasses" is a particularly
effective teaching tool. Does it work for you?

You're absolutely correct that casting the result of malloc() is not
necessary and should be avoided. Please don't give misleading advice
about *why* it's a bad idea.
 
K

Keith Thompson

Harald van Dijk said:
Herbert Rosenau wrote: [...]
A programmer who knows what he is doing will avoid any cast only
because the compiler gives a diagnostic as he knows that the
diagnostic shows an error he'd made and the error is NOT becaue he'd
forgotten to cast.

Here you go again with your overly broad claims. "Any" cast? Do you want to
clarify that?

I think what he meant here is that any cast that's added merely for
the purpose of shutting up a compiler diagnostic is a bad idea.

There are cases where casts are appropriate. There are far fewer such
cases than many C programmers seem to believe.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Keith said:
Harald van Dijk said:
Herbert Rosenau wrote: [...]
A programmer who knows what he is doing will avoid any cast only
because the compiler gives a diagnostic as he knows that the
diagnostic shows an error he'd made and the error is NOT becaue he'd
forgotten to cast.

Here you go again with your overly broad claims. "Any" cast? Do you want
to clarify that?

I think what he meant here is that any cast that's added merely for
the purpose of shutting up a compiler diagnostic is a bad idea.

Which is why I asked for clarification. My compiler generates a diagnostic
for

long long i = 1 << 40;

Adding a cast to shut it up:

long long i = (long long) 1 << 40;

is one way of fixing the code. (A suffix is another, but that is not an
option when using a variable.)
There are cases where casts are appropriate. There are far fewer such
cases than many C programmers seem to believe.

Probably so.
 
H

Herbert Rosenau

That's incorrect. In C90, "main()" is perfectly legal, and if I
recall correctly you'll find multiple instances of it in examples in
K&R2. C99 removed implicit int from the language, making "main()" a
constraint violation, but few compilers enforce this unless they're
specifically invoked in a strict C99-conforming mode.

It is deprecated anyway. Using that will hinder you to to to ANSI99
always. 16 years of standard should be enough to accept that.
"int main(void)" is better than "main()", and it has been since the
ANSI standard was introduced in 1989, but there's no need to overstate
the case.


Didn't we just go over this?

No, casting the result of malloc() does not invoke undefined behavior.
If there's no visible prototype for malloc() (the way to get one is
"#include <stdlib.h>"), then just *calling* malloc() invokes undefined
behavior, regardless of what you do with the result.

I've seen idiots removing #include <stdlib.h> and then failing into
undefined behavior on malloc().

Have you never learned to program failsave?
See the FAQ for more information.


I haven't found that calling people "dumbasses" is a particularly
effective teaching tool. Does it work for you?

You're absolutely correct that casting the result of malloc() is not
necessary and should be avoided. Please don't give misleading advice
about *why* it's a bad idea.
It IS a bad idea because
- undiefined behavior occures when stdlib is not included.
Having it yet included does not mean that somebody will remove
that sometimes later. Not anybody knows that already as
this group shows nearly dayly.
- undefined behavior is guaranteed because the standard dos not
tell that
- int is always the same size as void*
- the environemt uses even the same location to return int
and pointer values as the standard does allows that.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
K

Keith Thompson

Herbert Rosenau said:
It is deprecated anyway. Using that will hinder you to to to ANSI99
always. 16 years of standard should be enough to accept that.

I think you mean ANSI89 (also known as C89 or C90), not ANSI99.

Strictly speaking, I don't think implicit int was ever *formally*
deprecated. It was perfectly legal in C90, with (as far as I can
tell) no hint in the standard itself that it should be avoided, then
banned outright in C99. (My copy of the C90 standard is difficult to
search, so I might have missed something; if so, I'm sure someone will
post a citation.)

But as I said, and as you quoted (but you snipped the attribution
line; please don't do that):

I am not arguing, and I have never argued, that writing "main()"
rather than "int main(void)" is a good idea. I am making a very
narrow and specific point: your statement that it "Has to be
int main(void) since more than 16 years now" was incorrect.
It certainly *should* be but it doesn't *have* to be.

I'm trying to forestall claims of the form, "Well, my compiler
accepted it, so it must be ok."
I've seen idiots removing #include <stdlib.h> and then failing into
undefined behavior on malloc().

Have you never learned to program failsave?

What are you talking about? Have I ever said or implied that casting
the result of malloc() is a good idea?

I agree with you that casting the result of malloc() is almost always
a bad idea. (I added the word "almost" because there are rare
exceptions; they can be counted on the fingers of P.J. Plauger's left
hand.)
It IS a bad idea because
- undiefined behavior occures when stdlib is not included.
Having it yet included does not mean that somebody will remove
that sometimes later. Not anybody knows that already as
this group shows nearly dayly.
- undefined behavior is guaranteed because the standard dos not
tell that
- int is always the same size as void*
- the environemt uses even the same location to return int
and pointer values as the standard does allows that.

Yes, I know all that, and you should know that I know it.

Again, I was making a very narrow and specific point. Casting the
result of malloc() is a bad idea, but the cast itself *does not*
invoke undefined behavior.

Let me give you an example:

#include <stdlib.h>
int main(void)
{
int *ptr = (int*)malloc(sizeof *ptr);
if (ptr != NULL) {
*ptr = 42;
}
free(ptr);
return 0;
}

Let's ignore the fact that *ptr is assigned but never used.

This program exhibits bad style. The cast is entirely unnecessary,
and it should not be there. I would never write such a thing myself
except as a demonstration of bad style (or if, for some unlikely
reason, I had a real need to compile the code as either C or C++).

But the program is also entirely valid. It does not invoke undefined
behavior, and in fact it is strictly conforming.

I agree with your conclusion (don't cast the result of malloc()), but
by making incorrect statements about it you weaken your argument.

Now do you understand?
 
F

Flash Gordon

Harald said:
Keith said:
Harald van Dijk said:
Herbert Rosenau wrote: [...]
A programmer who knows what he is doing will avoid any cast only
because the compiler gives a diagnostic as he knows that the
diagnostic shows an error he'd made and the error is NOT becaue he'd
forgotten to cast.
Here you go again with your overly broad claims. "Any" cast? Do you want
to clarify that?
I think what he meant here is that any cast that's added merely for
the purpose of shutting up a compiler diagnostic is a bad idea.

Which is why I asked for clarification. My compiler generates a diagnostic
for

long long i = 1 << 40;

Here your compiler is not *required* to produce a diagnostic, but the
compiler writer(s) has chosen to be helpful. The numeric constant 1 fits
in to an int so it has type int. If you try to shift by more bits than
are in the type you are shifting (and very few systems have a 40 bit or
larger int type) then the behaviour is undefined and *anything* is
allowed to happen.
Adding a cast to shut it up:

long long i = (long long) 1 << 40;

is one way of fixing the code. (A suffix is another, but that is not an
option when using a variable.)

Adding the cast to shut the compiler up is wrong. Adding the cast
because it actually fixes the real problem by converting 1 to a large
enough type to support a 40 bit shift (or, as you suggest, a variable of
type int where you cannot use a suffix) is the right thing to do.

Of course, looking just at the code one cannot in this case see if you
added the cast for the right reason or the wrong reason. However, this
is one of those rare instances where the cast is a correct solution.
Probably so.

The experience of this group (and my own personal experience) support
Keith's assertion.
 
D

Dave Thompson

That's incorrect. In C90, "main()" is perfectly legal, and if I
recall correctly you'll find multiple instances of it in examples in
K&R2. C99 removed implicit int from the language, making "main()" a
constraint violation, but few compilers enforce this unless they're
specifically invoked in a strict C99-conforming mode.
<pedantic=super> syntax error not cv. As part of the deletion of
implicit int, C99 made (nonempty) declaration-specifiers mandatory in
a function-definition where C89 had them optional. They were already
mandatory in a syntactic 'declaration' which covers everything else,
but not required to contain a type specifier (i.e. could be just
storage class and/or qualifiers).

'extern main()' which was exactly equivalent in C89 is now in C99
presumably a constraint violation, because the declaration-specifiers
element is present but fails to include a type specifier. Although
6.7.2p2 is imprecisely worded and it could be read as UB-by-omission,
but that is so inconsistent with the obvious intent I reject it.

</> <AOL> I concur that 'int main (void)' is better.

- David.Thompson1 at worldnet.att.net
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top