Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Problem in printing string, created in another function.

Reply
Thread Tools

Problem in printing string, created in another function.

 
 
DanielJohnson
Guest
Posts: n/a
 
      01-04-2009
I am trying to print a int8_t (8 bits) in binary. Following is my
code. While I can print the values successfully within the function
call but when I try to print the same in main, garbage gets printed.
This makes me feel that since I assign retval memory using automatic
memory allocation in print8bits, after the function exits, that memory
is deallocated. Should I actually use malloc/calloc to assign memory
to retval so that even after function exits the value is still there.
Please advise.

Is there a better way to write and return values in such scenarios
where a function allocates the memory and the main just prints it.

Thanks for your replies.


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

#define CHAR_BIT 8

char *print8bits(int8_t a){
int8_t mask = 1;
char retval[] = "00000000\0";
int i, j = sizeof(a)* CHAR_BIT -1;
for(i = 0; i < sizeof(int8_t) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 8 bit integer = %s, %d\n", retval, a); //prints
fine
printf("Address of retval = %p\n", retval); //Address are same in
both the places
return retval;
}

int main()
{
char *temp = print8bits(-15); // I want to print -15 as 11110001.
printf("Address of retval in main = %p\n", temp); //Address are
same in both the places
printf("Printing 8 bit integer: %s\n", temp); // prints garbage
return 0;
}
 
Reply With Quote
 
 
 
 
Eric Sosman
Guest
Posts: n/a
 
      01-04-2009
DanielJohnson wrote:
> I am trying to print a int8_t (8 bits) in binary. Following is my
> code. While I can print the values successfully within the function
> call but when I try to print the same in main, garbage gets printed.
> This makes me feel that since I assign retval memory using automatic
> memory allocation in print8bits, after the function exits, that memory
> is deallocated. [...]


You're on the trail of the problem. See Question 7.5a in
the comp.lang.c Frequently Asked Questions (FAQ) list at
<http://www.c-faq.com/>.

--
Eric Sosman
lid
 
Reply With Quote
 
 
 
 
DanielJohnson
Guest
Posts: n/a
 
      01-04-2009
I forgot to add that the compiler prints the following warning when I
compiled it using gcc 4.2.

print_bytes_in_binary.c: In function ‘print8bits’:
print_bytes_in_binary.c:18: warning: function returns address of local
variable

Sorry for not providing complete information in my first post.

Thanks.
 
Reply With Quote
 
JC
Guest
Posts: n/a
 
      01-04-2009
On Jan 4, 4:31*pm, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
> DanielJohnson wrote:
> > I am trying to print a int8_t (8 bits) in binary. Following is my
> > code. While I can print the values successfully within the function
> > call but when I try to print the same in main, garbage gets printed.
> > This makes me feel that since I assign retval memory using automatic
> > memory allocation in print8bits, after the function exits, that memory
> > is deallocated. [...]

>
> * * *You're on the trail of the problem. *See Question 7.5a in
> the comp.lang.c Frequently Asked Questions (FAQ) list at
> <http://www.c-faq.com/>.


@DanielJohnson:

A possible approach is to have the caller supply the buffer; you can
still return a pointer to the buffer if you want to be able to call
the function in line:


char * print8bits (int8_t a, char *dest, int destbytes) {
/* convert and store in dest, do not write more that destbytes */
return dest;
}


Then the usage is:


int main (void) {
char temp[9];
printf("it's %s\n", print8bits(-15, temp, sizeof(temp)));
printf("it's still %s\n", temp);
return 0;
}


Note that passing the length of the buffer to the function lets the
function stop if it's going to write past the end of the buffer, but
if you know that your function will never write more than a certain
number of bytes, you could leave the length out and simply require
that the supplied buffer be at least 9 bytes long (or whatever). It's
usually a good idea to pass the buffer length, though, you never know
how things will change in the future.


Jason
 
Reply With Quote
 
DanielJohnson
Guest
Posts: n/a
 
      01-04-2009

> * * *You're on the trail of the problem. *See Question 7.5a in
> the comp.lang.c Frequently Asked Questions (FAQ) list at
> <http://www.c-faq.com/>.
>
> --
> Eric Sosman
> esos...@ieee-dot-org.invalid


Thanks for quick pointer to the right place and my bad that I did not
look it up before posting.

By using static retval and malloc(), I can overcome the problem.

A quick question, how can I initialize value using malloc(). For
example, following is not valid.

char *retval = malloc(CHAR_BIT + 1);
retval = "00000000\0";

Is there a terse way of doing it ? I know I could do in a for loop by
assigning retval[i] a value of '0' each time. I wanted to learn a
smarter way.

Thanks.

 
Reply With Quote
 
dj3vande@csclub.uwaterloo.ca.invalid
Guest
Posts: n/a
 
      01-04-2009
In article <f6003b62-3bcd-415b-9dca->,
DanielJohnson <> wrote:
>I am trying to print a int8_t (8 bits) in binary. Following is my
>code. While I can print the values successfully within the function
>call but when I try to print the same in main, garbage gets printed.
>This makes me feel that since I assign retval memory using automatic
>memory allocation in print8bits, after the function exits, that memory
>is deallocated.


Exactly.

> Should I actually use malloc/calloc to assign memory
>to retval so that even after function exits the value is still there.
>Please advise.


That's one way to solve the problem.
If you do that, the caller will need to free the memory after it's
finished using it.


>Is there a better way to write and return values in such scenarios
>where a function allocates the memory and the main just prints it.


Other possible solutions:

(1) Make the array you format into static.
This imposes some nontrivial restrictions on how the returned pointer
is used, but makes things most convenient for the caller when those
restrictions are satisfied.
The caller MUST completely finish using the buffer you formatted the
string into before the next time the formatting routine is called,
because the previous value will be overwritten every time it gets
called.
Also, it will be Very Difficult to make this thread-safe, if that's
something you're concerned about. (Both the call and the use of the
returned buffer need to be serialized, so you can't do it inside the
formatting code.)

(2) Require the caller to give you a buffer to format into.
This is probably the one I'd use.
It makes things a little bit less convenient for the caller (you need
to allocate a working buffer there, even if all you're going to do is
give the string to printf), but it deals with the storage-duration
problems that automatic or static allocation in the formatting code
have, and leaving memory management entirely up to the caller makes
reading the code easier, since it's all in one place. (It's also
likely that the caller knows better than the library code what the best
way to allocate the memory is.)
If the caller is providing the buffer, you also need to make sure the
buffer is big enough for what you're putting into it. For fixed sizes,
documenting it as "needs to provide a buffer at least N bytes long" is
fine; otherwise, take a length argument and return an error if you
don't have enough space.



[Code with all but the relevant bits snipped:]

>char *print8bits(int8_t a){

[...]
> char retval[] = "00000000\0";

[...]
> return retval;
>}



dave

--
Dave Vandervies dj3vande at eskimo dot com
If you think you know how to do something better, fer Crissake go do it
and prove it to the rest of us. Meanwhile, we'll muddle along with the
stuff that works. --P.J. Plauger in comp.lang.c++
 
Reply With Quote
 
dj3vande@csclub.uwaterloo.ca.invalid
Guest
Posts: n/a
 
      01-04-2009
In article <fa4b49a2-434c-492a-a559->,
DanielJohnson <> wrote:

>A quick question, how can I initialize value using malloc(). For
>example, following is not valid.
>
>char *retval = malloc(CHAR_BIT + 1);
>retval = "00000000\0";
>
>Is there a terse way of doing it ? I know I could do in a for loop by
>assigning retval[i] a value of '0' each time. I wanted to learn a
>smarter way.


strcpy().


dave

--
Dave Vandervies dj3vande at eskimo dot com
If you think you know how to do something better, fer Crissake go do it
and prove it to the rest of us. Meanwhile, we'll muddle along with the
stuff that works. --P.J. Plauger in comp.lang.c++
 
Reply With Quote
 
Stephen Sprunk
Guest
Posts: n/a
 
      01-04-2009
DanielJohnson wrote:
> I forgot to add that the compiler prints the following warning when I
> compiled it using gcc 4.2.
>
> print_bytes_in_binary.c: In function ‘print8bits’:
> print_bytes_in_binary.c:18: warning: function returns address of local
> variable


This is exactly what your problem is; be thankful that your compiler
warned you, since it isn't required to.

In short, your "retval" variable ceases to exist when the function
returns. When you later tell printf() to access that variable, you will
get undefined behavior (e.g. printing garbage). There are numerous ways
to fix the problem, but the first step is recognizing what's wrong

> Sorry for not providing complete information in my first post.


The error was obvious to most of us without it, fortunately. You
provided (almost) compilable code that exhibits the problem, which is
better than many folks do when asking for help...

S
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      01-04-2009
DanielJohnson wrote:
>> You're on the trail of the problem. See Question 7.5a in
>> the comp.lang.c Frequently Asked Questions (FAQ) list at
>> <http://www.c-faq.com/>.
>>
>> --
>> Eric Sosman
>> esos...@ieee-dot-org.invalid

>
> Thanks for quick pointer to the right place and my bad that I did not
> look it up before posting.
>
> By using static retval and malloc(), I can overcome the problem.
>
> A quick question, how can I initialize value using malloc(). For
> example, following is not valid.
>
> char *retval = malloc(CHAR_BIT + 1);
> retval = "00000000\0";
>
> Is there a terse way of doing it ? I know I could do in a for loop by
> assigning retval[i] a value of '0' each time. I wanted to learn a
> smarter way.


The character most easily overlooked is the rightmost,
where you must deposit a '\0'. In your code, this would be
most easily done by changing the calculation of `j' and
adding one line:

int i, j = sizeof(a)* CHAR_BIT; /* -1 removed */
retval[j--] = '\0'; /* added */

For the remaining digits, you could add an `else' to
your existing `if':

if (a & mask)
retval[j] = '1';
else /* added */
retval[j] = '0'; /* added */

Alternatively, you could use the ternary operator:

retval[j] = (a & mask) ? '1' : '0';

A slightly briefer and trickier way would be:

retval[j] = '1' - !(a & mask);

Finally, you might consider getting rid of `mask':
instead of shifting it successively to the left, consider
shifting `a' rightward so the bits slide successively into
the ones' place. Then you could write

retval[j] = '0' + (a & 1);

This last suggestion has a flaw: right-shifting a negative
value gives an implementation-defined result. But you've
already chosen to ignore what happens when you try to store
the value 128 in `mask' (whose maximum is only 127), so I
suspect you'd be willing to take your chances on the shift,
too.

--
Eric Sosman
lid
 
Reply With Quote
 
DanielJohnson
Guest
Posts: n/a
 
      01-04-2009
> * * *Alternatively, you could use the ternary operator:
>
> * * * * retval[j] = (a & mask) ? '1' : '0';
>
> * * *A slightly briefer and trickier way would be:
>
> * * * * retval[j] = '1' - !(a & mask);
>
> * * *Finally, you might consider getting rid of `mask':
> instead of shifting it successively to the left, consider
> shifting `a' rightward so the bits slide successively into
> the ones' place. *Then you could write
>
> * * * * retval[j] = '0' + (a & 1);
>
> This last suggestion has a flaw: right-shifting a negative
> value gives an implementation-defined result. *But you've
> already chosen to ignore what happens when you try to store
> the value 128 in `mask' (whose maximum is only 127), so I
> suspect you'd be willing to take your chances on the shift,
> too.
>
> --
> Eric Sosman
> esos...@ieee-dot-org.invalid


Thanks for all the cool tips and suggestions. Since you mentioned if I
was interested only in the values up to 2^n-1, this is what I was
trying to do.I was trying to understand the bigger problem, i.e., how
different architectures interpret the bytes internally. I was trying
to understand how a 32 bit float stores a number say 3.1422357234
internally in its 32 bits, and thats why I wrote this program. I
wanted to understand how positive and negative (2s complement) are
stored internally. Following is my code.

I hate to post this much amount of code but I want to get suggestions
on how to write better code, and if there are any obvious mistakes in
the programs that would give me incorrect results and hence my
understanding about these issues wouldn't be correct.


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

#define CHAR_BIT 8

void print8bits(int8_t a){
int8_t mask = 1;
char retval[] = "00000000\0";
int i, j = sizeof(a)* CHAR_BIT -1;
for(i = 0; i < sizeof(int8_t) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 8 bit integer = %s, %d\n", retval, a);
}

char *print8bitsW(int8_t a){
int8_t mask = 1;
char *retval = malloc(9);
memcpy(retval, "00000000\0", strlen("00000000\0"));
int i, j = sizeof(a)* CHAR_BIT -1;
for(i = 0; i < sizeof(int8_t) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 8 bit integer = %s, %d\n", retval, a);
return retval;
}
void print16bits(int16_t a){
int16_t mask = 1;
char retval[] = "0000000000000000\0";
int i, j = sizeof(a) * CHAR_BIT - 1;
for(i = 0; i < sizeof(a) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 16 bit integer = %s, %d\n", retval, a);
}

void print32bits(int32_t a){
int32_t mask = 1;
char retval[] = "00000000000000000000000000000000\0";
int i, j = sizeof(a) * CHAR_BIT - 1;
for(i = 0; i < sizeof(a) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 32 bit integer = %s, %d\n", retval, a);
}

void printfloat(float a){
int32_t mask = 1;
char retval[] = "00000000000000000000000000000000\0";
int i, j = sizeof(a) * CHAR_BIT - 1;
uint32_t *p = (uint32_t *) &a;
for(i = 0; i < sizeof(a) * CHAR_BIT; i++)
{
if (*p & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 32 bit float = %s, %f\n", retval, a);
}

void printdouble(double a){
int32_t mask;
char retval[] =
"0000000000000000000000000000000000000000000000000 000000000000000\0";
int i, j = sizeof(a) * CHAR_BIT - 1, k;
uint32_t *p = (uint32_t *) &a;
/*
* p now points to the last 32 bit of the 96 bits. After each
* iteration we consider the lower 32 bits. For example, in first
* iteration we consider bbits from 95 to 64, then 63 to 32 and
* finally 31 to 0.
*/
p += (sizeof(a)/sizeof(mask))-1;
for (k = 0; k < (sizeof(a)/sizeof(mask)); k++){
p = p - k;
mask = 1;
for(i = 0; i < sizeof(mask) * CHAR_BIT; i++)
{
if (*p & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
}

printf("Printing 64 bit doble = %s, %lf\n", retval, a);
}
void printlongdouble(long double a){
int32_t mask;
char retval[] =
"0000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000\0" ;
int i, j = sizeof(a) * CHAR_BIT - 1, k;
uint32_t *p = (uint32_t *) &a;
/*
* p now points to the last 32 bit of the 96 bits. After each
* iteration we consider the lower 32 bits. For example, in first
* iteration we consider bbits from 95 to 64, then 63 to 32 and
* finally 31 to 0.
*/
p += (sizeof(a)/sizeof(mask))-1;
for (k = 0; k < (sizeof(a)/sizeof(mask)); k++){
p = p - k;
mask = 1;
for(i = 0; i < sizeof(mask) * CHAR_BIT; i++)
{
if (*p & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
}

printf("Printing 96 bit long doble = %s, %Lf\n", retval, a);
}

void printlong(long a){
long mask = 1;
char retval[] = "00000000000000000000000000000000\0";
int i, j = sizeof(a) * CHAR_BIT - 1;
for(i = 0; i < sizeof(a) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 32 bit long = %s, %ld\n", retval, a);
}

void printlonglong(long long a){
long long mask = 1;
char retval[] =
"0000000000000000000000000000000000000000000000000 000000000000000\0";
int i, j = sizeof(a) * CHAR_BIT - 1;
for(i = 0; i < sizeof(a) * CHAR_BIT; i++)
{
if (a & mask)
retval[j] = '1';
mask = mask << 1;
j--;
}
printf("Printing 64 bit long long = %s, %lld\n", retval, a);
}
int main()
{
print8bits(5);
print8bits(-5);
print16bits(123);
print16bits(-123);
print32bits(27345234);
print32bits(-27345234);
printfloat(3.14);
printfloat(-3.14);
printfloat(1265654.3414);
printfloat(-1265654.3414);
printlong(1234126534);
printlong(-1234126534);
printdouble(423432.42342342);
printdouble(-423432.42342342);
printlonglong(-65656361);
printlonglong(65656361);
printlongdouble(-1765347347537.234234234);
printlongdouble(1765347347537.234234234);
return 0;
}

I don't expect you to browse the whole code but if you could point out
any obvious mistakes, that would be great.

Thanks to all of you for your replies.

Daniel
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Affecting a dynamically created drop down from another dynamically created drop down. msimmons ASP .Net 0 07-16-2009 03:17 PM
brochure printing,online yearbook,printing,books printing,publishing elie Computer Support 0 08-21-2007 05:52 AM
brochure printing,online yearbook,printing,books printing,publishing elie Computer Support 0 08-21-2007 05:50 AM
brochure printing,online yearbook,printing,books printing,publishing elie Computer Support 0 08-21-2007 05:28 AM
brochure printing,online yearbook,printing,books printing,publishing elie Computer Support 0 08-18-2007 10:11 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 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 50 51 52 53 54 55 56 57