All of lore.kernel.org
 help / color / mirror / Atom feed
* Newbie Trouble with pointers and structures.
@ 2003-08-09 18:16 Eric
  2003-08-09 20:49 ` Glynn Clements
  2003-08-09 21:02 ` Eric
  0 siblings, 2 replies; 4+ messages in thread
From: Eric @ 2003-08-09 18:16 UTC (permalink / raw)
  To: linux-c-programming

Hello:
	I am a newbie who is trying to teach himself C programming and I am having 
trouble modifying structure contents. I want the function setoption() to take 
a pointer to a pointer in a structure and modify it without needing to return 
a value (although currently it does). The function works correctly and GDB 
shows that *Option has been set to *String. However, when the function 
returns the pointer in the structure has not been modified. Here are the 
relevant code pieces.

in file vpn.c (where main() is)

structure definition (declared global in vpn.c):
struct {
	/* Structure to hold configuration parameters. The options are set to
	their defaults below. The options that need to be built will be set in
	detdefaultconfig(). The defaults here are mainly to initilize the
	pointers and any changes will be overridden by setdefaultconfig(); */
	// General Options
 	char *PPPDevice;
	char *VPNHost;
	char *LocalIP;
	char *RemoteIP;
	char *PPPDOptions;
	int Delay;
	//SSH Specific
	char *SSHCipher;
	char *SSHLogin;
	char *SSHOptions;
	int SSHPort;
	char *SSHIdentityFilename;
	//Files
	char *VPNPIDFilename;
	FILE *VPNPIDFile;
	char *LogFilename;
	FILE *LogFile;
} ConfigOptions = { NULL, NULL, NULL, NULL, NULL, 0,\
		    NULL,NULL,NULL,0, NULL,NULL, NULL,NULL,NULL};

extern char *setoption(char *Option,const char *String);

setoption is called like this from vpn.c: 
setoption(ConfigOptions.LogFilename,"/var/log/vpn.log");

in file helpers.c:
char *setoption(char *Option,const char *String){
	int achar = sizeof(char);
	/* This function takes a pointer to a structure element and sets it to
	the given string. Takes care of memory allocation with free and malloc. We
	can just give it the option and the string and let it play. Saves time. */
	if (Option != NULL){
		free(Option);
	}
	Option = (char *)malloc(achar * strlen(String));
	if (Option == NULL){
		fprintf(stderr,"Error Allocating Memory in setoption");
	}
	//Copy the new string.
	strcpy(Option,String);
}

After the function returns. GDB print ConfigOptions.LogFilename shows 0x0 
address (NULL).Obviously this is what it has been initialized to in the 
beginning. I know that
ConfigOptions.LogFilename = \ 
setoption(ConfigOptions.LogFilename,"/var/log/vpn.log");
will work....but thats not quite how I want to do it. And besides, its longer 
and kinda clunky compared to giving it the pointer only once.

According to my knowledge I should be modifying the Pointer in the structure, 
but according to gdb It seems that I am missing something.

Any help would be greatly appreciated. 

----------------------
Eric Bambach   
Eric (at) CISU (dot) net 
----------------------

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Newbie Trouble with pointers and structures.
  2003-08-09 18:16 Newbie Trouble with pointers and structures Eric
@ 2003-08-09 20:49 ` Glynn Clements
  2003-08-09 21:02 ` Eric
  1 sibling, 0 replies; 4+ messages in thread
From: Glynn Clements @ 2003-08-09 20:49 UTC (permalink / raw)
  To: eric; +Cc: linux-c-programming


Eric wrote:

> 	I am a newbie who is trying to teach himself C programming and I am having 
> trouble modifying structure contents. I want the function setoption() to take 
> a pointer to a pointer in a structure and modify it without needing to return 
> a value (although currently it does). The function works correctly and GDB 
> shows that *Option has been set to *String. However, when the function 
> returns the pointer in the structure has not been modified. Here are the 
> relevant code pieces.
> 
> in file vpn.c (where main() is)
> 
> structure definition (declared global in vpn.c):
> struct {

> 	char *LogFilename;

> } ConfigOptions = { NULL, NULL, NULL, NULL, NULL, 0,\
> 		    NULL,NULL,NULL,0, NULL,NULL, NULL,NULL,NULL};
> 
> extern char *setoption(char *Option,const char *String);
> 
> setoption is called like this from vpn.c: 
> setoption(ConfigOptions.LogFilename,"/var/log/vpn.log");
> 
> in file helpers.c:
> char *setoption(char *Option,const char *String){
> 	int achar = sizeof(char);

sizeof(char) is *always* 1; there is no need to compute it.

> 	/* This function takes a pointer to a structure element and sets it to
> 	the given string. Takes care of memory allocation with free and malloc. We
> 	can just give it the option and the string and let it play. Saves time. */
> 	if (Option != NULL){
> 		free(Option);
> 	}
> 	Option = (char *)malloc(achar * strlen(String));

The result of strlen() doesn't include the terminating NUL byte; you
have to add that yourself. But in this case, just use strdup().

> 	if (Option == NULL){
> 		fprintf(stderr,"Error Allocating Memory in setoption");
> 	}
> 	//Copy the new string.
> 	strcpy(Option,String);
> }
> 
> After the function returns. GDB print ConfigOptions.LogFilename shows 0x0 
> address (NULL).Obviously this is what it has been initialized to in the 
> beginning. I know that
> ConfigOptions.LogFilename = \ 
> setoption(ConfigOptions.LogFilename,"/var/log/vpn.log");
> will work....but thats not quite how I want to do it. And besides, its longer 
> and kinda clunky compared to giving it the pointer only once.
> 
> According to my knowledge I should be modifying the Pointer in the structure, 
> but according to gdb It seems that I am missing something.

Except for arrays, C uses call-by-value, i.e. the parameter variable
is distinct from the argument expression; modifying the parameter
within the callee won't affect the argument in the caller. I'll give
an example:

	#include <stdio.h>
	
	void foo(int x)
	{
		printf("foo[1]: x = %d\n", x);
		x++;
		printf("foo[2]: x = %d\n", x);
	}
	
	void bar(void)
	{
		int x = 1;
		printf("bar[1]: x = %d\n", x);
		foo(x);
		printf("bar[2]: x = %d\n", x);
	}
	
	int main(void)
	{
		bar();
		return 0;
	}

This will print:

	bar[1]: x = 1
	foo[1]: x = 1
	foo[2]: x = 2
	bar[2]: x = 1

If you want the callee to modify something from the caller's scope,
you have to pass a pointer to the thing which you wish it to modify,
e.g.:

	#include <stdio.h>
	
	void foo(int *px)
	{
		printf("foo[1]: *px = %d\n", *px);
		(*px)++;
		printf("foo[2]: *px = %d\n", *px);
	}
	
	void bar(void)
	{
		int x = 1;
		printf("bar[1]: x = %d\n", x);
		foo(&x);
		printf("bar[2]: x = %d\n", x);
	}
	
	int main(void)
	{
		bar();
		return 0;
	}

prints:

	bar[1]: x = 1
	foo[1]: *px = 1
	foo[2]: *px = 2
	bar[2]: x = 2

So, in your specific case, you need e.g.:

	char *setoption(char **pOption, const char *String)
	{
		char *Option = *pOption;
		if (Option)
			free(Option);
		Option = strdup(String);
		if (!Option)
			fprintf(stderr,"Error Allocating Memory in setoption");
		*pOption = Option;
	}

For this, you have to pass the address of the field, i.e.:

	setoption(&ConfigOptions.LogFilename,"/var/log/vpn.log");

-- 
Glynn Clements <glynn.clements@virgin.net>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Newbie Trouble with pointers and structures.
  2003-08-09 18:16 Newbie Trouble with pointers and structures Eric
  2003-08-09 20:49 ` Glynn Clements
@ 2003-08-09 21:02 ` Eric
  2003-08-09 22:55   ` Glynn Clements
  1 sibling, 1 reply; 4+ messages in thread
From: Eric @ 2003-08-09 21:02 UTC (permalink / raw)
  To: linux-c-programming

	Ok, here is a less complicated post.My other one is lengthy but this SIMPLE 
test program illustrates my point and works off the same concept.I know the 
test code is messy but it illustrates my concept. I would like to know why 
this very simple  test program outputs:
test
test

instead of what i would expect:
test 
modifed

here is the code.

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
int main();
int modify(char *p);
int main(){
        char *p = "test";
        puts(p);
        modify(p);
        puts(p);
}

int modify(char *p){
        p = malloc(sizeof(char) * 20);
        strcpy(p,"modified");
}

I am sure I am missing some simple concept...but can anyone explain what that 
concept is? I have a few thick books on C and cannot deduce what the problem 
would be. The code below SHOULD be of the same concept and it produces the 
expected result. It's output is 
1
2

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

int main();
int modify(int *p);

int main(){
        int *p;
        p = malloc(sizeof(int));
        *p = 1;
        printf("%d\n",*p);
        modify(p);
        printf("%d\n",*p);
}

int modify(int *p){
        free(p);
        p = malloc(sizeof(int));
        *p = 2;
}
----------------------
Eric Bambach   
Eric (at) CISU (dot) net 
----------------------

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Newbie Trouble with pointers and structures.
  2003-08-09 21:02 ` Eric
@ 2003-08-09 22:55   ` Glynn Clements
  0 siblings, 0 replies; 4+ messages in thread
From: Glynn Clements @ 2003-08-09 22:55 UTC (permalink / raw)
  To: eric; +Cc: linux-c-programming


Eric wrote:

> 	Ok, here is a less complicated post.My other one is lengthy but this SIMPLE 
> test program illustrates my point and works off the same concept.I know the 
> test code is messy but it illustrates my concept. I would like to know why 
> this very simple  test program outputs:
> test
> test
> 
> instead of what i would expect:
> test 
> modifed
> 
> here is the code.
> 
> #include <stdio.h>
> #include <stdarg.h>
> #include <stdlib.h>
> #include <string.h>
> int main();
> int modify(char *p);
> int main(){
>         char *p = "test";
>         puts(p);
>         modify(p);
>         puts(p);
> }
> 
> int modify(char *p){
>         p = malloc(sizeof(char) * 20);
>         strcpy(p,"modified");
> }

The parameter p of modify is a different variable to the local
variable p in main(). modify(p) passes a copy of the pointer to
modify; modify allocates additional memory, and overwrites the
parameter p with the pointer to that memory. It does not modify the
local variable p in main(), or the memory to which that points.

> I am sure I am missing some simple concept...but can anyone explain what that 
> concept is?

Call-by-value. In the above code, modify allocates new memory, copies
the string "modified" into it, then loses the reference when it
returns. The memory is still allocated, it still contains the string
"modified", but there is no longer any way to refer to it. All the
while, the local variable p within main continues to point at the
string "test".

To get the result which you desire, you would have to do this:

int main(){
        char *p = "test";
        puts(p);
        modify(&p);
        puts(p);
}

int modify(char **p){
        *p = malloc(sizeof(char) * 20);
        strcpy(*p,"modified");
}

Here, main passes a pointer to the local variable p, and modify
changes the memory to which that pointer points (which happens to be
main's local variable p).

This would also work:

int main(){
        char p[9] = "test";
        puts(p);
        modify(p);
        puts(p);
}

int modify(char *p){
        strcpy(p,"modified");
}

Here, p is an array, and main passes a pointer to the start of the
array. modify overwrites the contents of the array.

Yet another example which would work:

int main(){
        char *p;
	p = malloc(9);
	strcpy(p, "test");
        puts(p);
        modify(p);
        puts(p);
}

int modify(char *p){
        strcpy(p,"modified");
}

> I have a few thick books on C and cannot deduce what the problem 
> would be. The code below SHOULD be of the same concept and it produces the 
> expected result. It's output is 
> 1
> 2
> 
> #include <stdarg.h>
> #include <stdlib.h>
> #include <string.h>
> 
> int main();
> int modify(int *p);
> 
> int main(){
>         int *p;
>         p = malloc(sizeof(int));
>         *p = 1;
>         printf("%d\n",*p);
>         modify(p);
>         printf("%d\n",*p);
> }
> 
> int modify(int *p){
>         free(p);
>         p = malloc(sizeof(int));
>         *p = 2;
> }

The behaviour of this code is undefined. It is only by coincidence
that you get the behaviour which you expect.

Specifically, malloc() just happens to return a pointer to the memory
which was just freed, and to which the local variable p in main still
happens to point. malloc() is not guaranteed to behave this way.

-- 
Glynn Clements <glynn.clements@virgin.net>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2003-08-09 22:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-09 18:16 Newbie Trouble with pointers and structures Eric
2003-08-09 20:49 ` Glynn Clements
2003-08-09 21:02 ` Eric
2003-08-09 22:55   ` Glynn Clements

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.