Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > function returning pointer

Reply
Thread Tools

function returning pointer

 
 
Ron Peterson (012ED25E)
Guest
Posts: n/a
 
      11-19-2009
I don't understand the difference between the following:

void foo( char *s ) {
s = malloc( 10 );
}

and

char * bar( char * s ) {
s = malloc( 10 );
return s;
}

If I now have char *a, and I say foo( a ), how is that different from
saying a = bar( a )? I've deduced from some code that I'm writing
that I should use the second form; but why?
 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      11-19-2009
On 2009-11-19, Ron Peterson (012ED25E) <> wrote:
> void foo( char *s ) {
> s = malloc( 10 );
> }


This allocates memory, but has no other effect.

When you call a function, it is given a COPY of the arguments you pass
it. This function modifies the local variable 's' that is its local copy
of the parameter. It does not modify anything else.

> char * bar( char * s ) {
> s = malloc( 10 );
> return s;
> }


This does the same thing -- but it returns the pointer you allocated,
so you can use it later.

> If I now have char *a, and I say foo( a ), how is that different from
> saying a = bar( a )? I've deduced from some code that I'm writing
> that I should use the second form; but why?


Imagine a function:
void foo2(int s) {
s = 23;
}

Because foo(a) doesn't change a, any more than foo2(3) changes 3.

-s
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
 
Ioannis Vranos
Guest
Posts: n/a
 
      11-19-2009
Ron Peterson (012ED25E) wrote:

> I don't understand the difference between the following:
>
> void foo( char *s ) {
> s = malloc( 10 );
> }


This creates a local char pointer variable named s, that is a copy of the
pointer variable you pass to the function.

Then you allocate 10 Bytes in the free store if the malloc() call is
successful, which are leaked when the execution of the program reaches the
end of the scope of function foo().

That is, the char pointer variable s is destroyed, but the allocated space
of the 10 Bytes is not released.


The correct version for the above is:


#include <stdlib.h>


void foo( char *s ) {
s = malloc( 10 );

free(s);
}




>
> and
>
> char * bar( char * s ) {
> s = malloc( 10 );
> return s;
> }
>
> If I now have char *a, and I say foo( a ), how is that different from
> saying a = bar( a )? I've deduced from some code that I'm writing
> that I should use the second form; but why?



I do not understand the question. What you probably want to do is the style:


#include <stdlib.h>


char * bar(void) {

char *s;

/* ... */

s = malloc( 10 );

// ...

return s;
}




--
Ioannis Vranos

C95 / C++03 Software Developer

http://www.cpp-software.net
 
Reply With Quote
 
Ron Peterson (012ED25E)
Guest
Posts: n/a
 
      11-19-2009
On Nov 18, 11:17*pm, Seebs <usenet-nos...@seebs.net> wrote:

> When you call a function, it is given a COPY of the arguments you pass
> it.


Oh duh. I haven't done any C for so long I had a total brain freeze.
Of course. Thanks everyone.

-Ron-
 
Reply With Quote
 
Beej Jorgensen
Guest
Posts: n/a
 
      11-19-2009
Ron Peterson (012ED25E) <> wrote:
>char * bar( char * s ) {


The others have pointed out the errors here, but I wanted to note that
there is a common idiom in the C libs to return a copy of an
operated-upon item. For example:

char *strcpy(char *dest, const char *src);

which returns "dest" as opposed to returning void.

The idea is, I think, that the caller might want to use the result in
some other immediate capacity. A contrived example:

printf("%s\n", strcpy(foo, bar)); // prints foo

That being said, I don't think I've ever seen strcpy()'s return value
used.

-Beej

 
Reply With Quote
 
frank
Guest
Posts: n/a
 
      11-19-2009
On Wed, 18 Nov 2009 23:26:09 -0500, pete wrote:

> Ron Peterson (012ED25E) wrote:
>> I don't understand the difference between the following:
>>
>> void foo( char *s ) {
>> s = malloc( 10 );
>> }
>>
>> and
>>
>> char * bar( char * s ) {
>> s = malloc( 10 );
>> return s;
>> }
>>
>> If I now have char *a, and I say foo( a ), how is that different from
>> saying a = bar( a )? I've deduced from some code that I'm writing that
>> I should use the second form; but why?

>
> You should not use either form.
> The first doesn't work and the second makes no use of the value of the
> function call argument.
>
> Both of the following are workable:
>
> void bar( char **s )
> {
> *s = malloc( 10 );
> }
>
> char *bar( void )
> {
> char *s = malloc( 10 );
>
> return s;
> }


I tried to get the returns from malloc but hit a bump somewhere:

dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra malloc1.c -o out
malloc1.c: In function ‘main’:
malloc1.c:25: warning: unused variable ‘c’
dan@dan-desktop:~/source$ ./out
Segmentation fault
dan@dan-desktop:~/source$ cat malloc1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bar( char **s )
{
*s = malloc( 10 );
}

char *baz( void )
{
char *s = malloc( 10 );

return s;
}


int
main(void)
{
void bar ( char ** );
char * baz ( void );
char ** a;
char * b;
int c;

bar ( a );
b = baz( );
#if 0
c = * b;
strcpy(b, "qwerty");
printf ("%s\n", b);
#endif


return 0;
}
// gcc -std=c99 -Wall -Wextra malloc1.c -o out
dan@dan-desktop:~/source$

One other thing. I just tried to man indent to find the usage for
setting the tablength at 4, as pete had it for his code. How do you do
that?
--
frank

"Guns: yes, they are harmful."
 
Reply With Quote
 
Lew Pitcher
Guest
Posts: n/a
 
      11-20-2009
On November 19, 2009 18:53, in comp.lang.c, frank ()
wrote:
[snip]
> I tried to get the returns from malloc but hit a bump somewhere:
>
> dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra malloc1.c -o out
> malloc1.c: In function ‘main’:
> malloc1.c:25: warning: unused variable ‘c’
> dan@dan-desktop:~/source$ ./out
> Segmentation fault
> dan@dan-desktop:~/source$ cat malloc1.c
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> void bar( char **s )


Function bar accepts a pointer to a pointer-to-char, right?

> {
> *s = malloc( 10 );


Here, you take that pointer to a pointer-to char, find what it points to,
and change that value so that it now points to the data area you have
malloc()ed.

In other words,
Before the line,
s pointed to a pointer, and that pointer pointed somewher
After the line,
s still pointed to the same place, but the contents of that place have
been changed to now contain the value returned by malloc()

With me so far?

> }
>
> char *baz( void )
> {
> char *s = malloc( 10 );
>
> return s;
> }
>
>
> int
> main(void)
> {
> void bar ( char ** );
> char * baz ( void );
> char ** a;


Here, you allocate a as a pointer to pointer-to-char. But, you leave it
uninitialized; a doesn't point at anything in particular (it's value is
indeterminate).


> char * b;
> int c;
>
> bar ( a );


Now, you pass a, an unitialized pointer to bar(). Remember what bar() will
do; it will try to modify the area that this pointer points to.

But, this pointer has an indeterminate value; it /could/ point anywhere,
including outside of the space in which your program and it's data reside.

<off_topic>
Now, when a Unix process (that being the platform you are apparently
compiling and running on) tries to access memory outside of the bounds of
the process's memory map, Unix protects that memory, and sends a SIGSEGV
signal to the process. Uncaught, this SIGSEGV will cause the process to
abort, with a "Segmentation Violation" error message. That's what you got.
</off_topic>

The cure for your problem is to, prior to invoking function bar(),
*initialize* the pointer so that it points at a pointer-to-char.

Given your existing code, what you really wanted to do was...

a = &b;
bar ( a );

or, in shorter form

bar (&b);


> b = baz( );
> #if 0
> c = * b;
> strcpy(b, "qwerty");
> printf ("%s\n", b);
> #endif
>
>
> return 0;
> }
> // gcc -std=c99 -Wall -Wextra malloc1.c -o out
> dan@dan-desktop:~/source$
>
> One other thing. I just tried to man indent to find the usage for
> setting the tablength at 4, as pete had it for his code. How do you do
> that?


--
Lew Pitcher
Master Codewright & JOAT-in-training | Registered Linux User #112576
Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
---------- Slackware - Because I know what I'm doing. ------


 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-20-2009
frank <> writes:
[...]
> I tried to get the returns from malloc but hit a bump somewhere:

[...]
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> void bar( char **s )
> {
> *s = malloc( 10 );
> }
>
> char *baz( void )
> {
> char *s = malloc( 10 );
>
> return s;
> }
>
>
> int
> main(void)
> {
> void bar ( char ** );
> char * baz ( void );
> char ** a;
> char * b;
> int c;
>
> bar ( a );
> b = baz( );
> #if 0
> c = * b;
> strcpy(b, "qwerty");
> printf ("%s\n", b);
> #endif
>
>
> return 0;
> }

[...]

As Lew Pitcher already mentioned, the problem is that ``a'' is
uninitialized when you pass it to bar.

Since function arguments are passed by value, passing (the value of)
an uninitialized object to any function is bad news. In your main
function above, you declare ``a'', but you don't initialize it or
assign a value to it; you then pass it as an argument in ``bar(a)''.

This is equally bad regardless of whether ``a'' is a char, a pointer,
a pointer to a pointer, or any other type of object. The type of the
object is immaterial; referring to the value of an uninitialized
object is bad. (The word "bad" is admittedly vague. In this case,
it's undefined behavior; in some cases it might not be. But it's
almost certainly not what you want to do, unless examining garbage in
memory is your idea of a good time).

> One other thing. I just tried to man indent to find the usage for
> setting the tablength at 4, as pete had it for his code. How do you do
> that?


Search for the word "indentation" in the man page.

--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
frank
Guest
Posts: n/a
 
      11-21-2009
On Thu, 19 Nov 2009 19:04:56 -0500, Lew Pitcher wrote:

> On November 19, 2009 18:53, in comp.lang.c, frank


> Function bar accepts a pointer to a pointer-to-char, right?
>
>> {
>> *s = malloc( 10 );

>
> Here, you take that pointer to a pointer-to char, find what it points
> to, and change that value so that it now points to the data area you
> have malloc()ed.
>
> In other words,
> Before the line,
> s pointed to a pointer, and that pointer pointed somewher
> After the line,
> s still pointed to the same place, but the contents of that place have
> been changed to now contain the value returned by malloc()
>
> With me so far?


yup.
>> int
>> main(void)
>> {
>> void bar ( char ** );
>> char * baz ( void );
>> char ** a;

>
> Here, you allocate a as a pointer to pointer-to-char. But, you leave it
> uninitialized; a doesn't point at anything in particular (it's value is
> indeterminate).
>
>
>> char * b;
>> int c;
>>
>> bar ( a );

>
> Now, you pass a, an unitialized pointer to bar(). Remember what bar()
> will do; it will try to modify the area that this pointer points to.
>
> But, this pointer has an indeterminate value; it /could/ point anywhere,
> including outside of the space in which your program and it's data
> reside.
>
> <off_topic>
> Now, when a Unix process (that being the platform you are apparently
> compiling and running on) tries to access memory outside of the bounds
> of the process's memory map, Unix protects that memory, and sends a
> SIGSEGV signal to the process. Uncaught, this SIGSEGV will cause the
> process to abort, with a "Segmentation Violation" error message. That's
> what you got. </off_topic>
>
> The cure for your problem is to, prior to invoking function bar(),
> *initialize* the pointer so that it points at a pointer-to-char.
>
> Given your existing code, what you really wanted to do was...
>
> a = &b;
> bar ( a );
>
> or, in shorter form
>
> bar (&b);


Alright, thx Lew. When I try to work with indirection and do it from
scratch, I think I might resemble a beautiful animal like a caribou: 15
minutes after it's born, covered with afterbirth, wobbly on it's too-long
limbs.

So when you have a constructor that uses char **, what you want to do is
declare a pointer to char and then pass it preceded by the reference
operator, & .

I figured I would have this correct if I could print out the vlaues that
malloc returned. Indeed, it's plum necessary for robust code to at least
check for a positive value.

I've got the parts here, dan@dan-desktop:~/source$ gcc -std=c99 -Wall -
Wextra malloc1.c -o out
malloc1.c: In function ‘bar’:
malloc1.c:8: warning: initialization makes integer from pointer without a
castdan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra malloc1.c -o out
malloc1.c: In function ‘bar’:
malloc1.c:8: warning: initialization makes integer from pointer without a
cast
malloc1.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has
type ‘char **’
malloc1.c:8: warning: unused variable ‘r’
malloc1.c: In function ‘main’:
malloc1.c:26: warning: unused variable ‘r’
dan@dan-desktop:~/source$ ./out
-1081554784
qwerty
0
dan@dan-desktop:~/source$ cat malloc1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bar( char **s )
{
*s = malloc( 10 );
int r = &s;
printf("%d\n", s);
}

char *baz( void )
{
char *s = malloc( 10 );

return s;
}


int
main(void)
{
void bar ( char ** );
char * baz ( void );
char * b;
int c, r;

bar ( &b );
b = baz( );
#if 1
c = * b;
strcpy(b, "qwerty");
printf ("%s\n", b);
printf ("%d\n", c);
#endif


return 0;
}
// gcc -std=c99 -Wall -Wextra malloc1.c -o out
dan@dan-desktop:~/source$

malloc1.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has
type ‘char **’
malloc1.c:8: warning: unused variable ‘r’
malloc1.c: In function ‘main’:
malloc1.c:26: warning: unused variable ‘r’
dan@dan-desktop:~/source$ ./out
-1081554784
qwerty
0
dan@dan-desktop:~/source$ cat malloc1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bar( char **s )
{
*s = malloc( 10 );
int r = &s;
printf("%d\n", s);
}

char *baz( void )
{
char *s = malloc( 10 );

return s;
}


int
main(void)
{
void bar ( char ** );
char * baz ( void );
char * b;
int c, r;

bar ( &b );
b = baz( );
#if 1
c = * b;
strcpy(b, "qwerty");
printf ("%s\n", b);
printf ("%d\n", c);
#endif


return 0;
}
// gcc -std=c99 -Wall -Wextra malloc1.c -o out
dan@dan-desktop:~/source$
but I seem to be unable to dereference:

dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra malloc1.c -o out
malloc1.c: In function ‘bar’:
malloc1.c:8: warning: initialization makes integer from pointer without a
cast
malloc1.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has
type ‘char **’
malloc1.c:8: warning: unused variable ‘r’
malloc1.c: In function ‘main’:
malloc1.c:26: warning: unused variable ‘r’
dan@dan-desktop:~/source$ ./out
-1081554784
qwerty
0
dan@dan-desktop:~/source$ cat malloc1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bar( char **s )
{
*s = malloc( 10 );
int r = &s;
printf("%d\n", s);
}

char *baz( void )
{
char *s = malloc( 10 );

return s;
}


int
main(void)
{
void bar ( char ** );
char * baz ( void );
char * b;
int c, r;

bar ( &b );
b = baz( );
#if 1
c = * b;
strcpy(b, "qwerty");
printf ("%s\n", b);
printf ("%d\n", c);
#endif


return 0;
}
// gcc -std=c99 -Wall -Wextra malloc1.c -o out
dan@dan-desktop:~/source$

>> One other thing. I just tried to man indent to find the usage for
>> setting the tablength at 4, as pete had it for his code. How do you do
>> that?


Any takers on this one? One problem with programs that have over fifty
options is that you can't find the one option that any indent program
really needs, i.e., the tab length.

--
frank

"Guns: yes, they are harmful."
 
Reply With Quote
 
frank
Guest
Posts: n/a
 
      11-21-2009
On Sat, 21 Nov 2009 20:29:14 +0100, Richard wrote:

> frank <> writes:
>
>> On Thu, 19 Nov 2009 19:04:56 -0500, Lew Pitcher wrote:
>>
>>>> One other thing. I just tried to man indent to find the usage for
>>>> setting the tablength at 4, as pete had it for his code. How do you
>>>> do that?

>>
>> Any takers on this one? One problem with programs that have over fifty
>> options is that you can't find the one option that any indent program
>> really needs, i.e., the tab length.

>
> It's good manners to snip a long post like that.


Oops, sorry. I didn't want to snip too much of Lew's comments, because
I'm not quite straightened out on this yet. I over-selected out of
terminal to get way too much of it.
>
> On my machine "info indent", open options summary and search for tab.
>
> ,----
> | `-tsN'
> | `--tab-sizeN'
> | Set tab size to N spaces.
> | *Note Indentation::.
> `----
>
> I guess you could have guessed "length" "size" or "tab" were pertinent
> search criteria :-;


dan@dan-desktop:~/source$ indent -i4 malloc1.c

This works.
--
frank

"Guns: yes, they are harmful."
 
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
Declaring static function returning pointer to extern function pembed2012 C Programming 1 02-27-2012 08:21 PM
function returning function pointer (recursive type) Mark Piffer C Programming 9 05-15-2009 07:54 AM
Function returning a function pointer? Protoman C++ 14 12-11-2005 07:11 PM
pointer to member function and pointer to constant member function Fraser Ross C++ 4 08-14-2004 06:00 PM
function pointer and member function pointer question glen stark C++ 2 10-10-2003 01:41 PM



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