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

typedef struct
{
	char firstName[50];
	char lastName[50];
	int age;
}Person;

void ModifyPerson(Person*);

int main()
{
	Person person;
	strcpy(person.firstName, "firstName");
	strcpy(person.lastName, "lastName");
	ModifyPerson(&person);
	printf("First Name=%s\nLast Name=%s\n",person.firstName, person.lastName);
	system("PAUSE");
}

void ModifyPerson(Person *p1)
{
	//This doesn't modify the original variable declared in main function
	Person person = *p1;
	strcpy(person.firstName, "Modified1");
	strcpy(person.lastName, "Modified1");
	
	//This does modify the original person variable
	strcpy((*p1).firstName, "Modified");
	strcpy((*p1).lastName, "Modified");	
}

In the above code, the first 3 lines in method ModifyPerson fails to modify the original "person" variable declared in main method. The changes made by the first 3 line of code in the ModifyPerson method is local to the variable. However the changes it makes using the last 2 line affects the original "person" variable created in main method.

Now what I'm trying to find out is if there is a way to work with *p1 within the ModifyPerson method. As you see, it's not always convenient to write (*p1) each time i want to use this variables value. Is there any other way round for this ?

Please help ! I'm new to C. I have been working with C# so far.

Recommended Answers

All 5 Replies

You could use

p1->lastName
p1->firstname

Person person = *p1;

This is copying the pointer address to the first 4 bytes of firstName in the newly created instance of Person, and then completely undone by line 27:

strcpy(person.firstName, "Modified1");

Which overwrites the 4 bytes written by the previous line of code with the given string constant.

If so, the compiler is ultimately treating line 26 as this:

Person person;

So the pointer to p1 is not even involved here, which explains why it does not change the values pointed to by p1 as jay1648 explained.

Here is my explanation on the different ways to access a pointer:

void ModifyPerson(Person *p1)
{
	// This technique, which you used in your code,
        // is the pointer dereferencing method to access
        // the contents of p1. Since the compiler knows 
        // p1 is a pointer, putting an asterisk in front
        // of it tells the compiler that you want the
        // value of the memory pointed to by the pointer.
        // The parenthesis are a way to isolate the
        // dereferenced pointer from the name of the
        // element of that structure you want to access.
        // The compiler knows the size and type of p1
        // so it also knows what you are trying to say
        // when you write "firstName" and "lastName"

	strcpy((*p1).firstName, "Modified");
	strcpy((*p1).lastName, "Modified");	

        // This technique is accessing a pointer as 
        // an array. All variables in C are really 
        // instances of an array of one element. When 
        // you have any pointer, you can tell it that 
        // you want the first element of the type of
        // value pointed to by that array, even if its
        // not an array. It will internally do some
        // math which simplifies to (*p1). Just make
        // sure that you don't put a number other than
        // zero in the array index.

	strcpy(p1[0].firstName, "Modified");
	strcpy(p1[0].lastName, "Modified");

        // This is the most common way to access 
        // pointer values. It is easy to read and quick
        // to implement. An arrow operator is called an
        // indirection. It will basically dereference the
        // variable you have to the left of the arrow.
        // Coming from C#, you probably would rather this
        // syntax.
	strcpy(p1->firstName, "Modified");
	strcpy(p1->lastName, "Modified");
}
commented: Nice explanation ! +0

Using it as p1->firstname is absolutely fine, and appears to be what I was looking for. At other sites I used to see this -> being used without realizing what's it used for.

I suppose I can't use this operator "->" with a variable which is not a pointer. And so this can't replace the "." operator in use. I'll test and find this out though.

Thanks to you gerard4143 and Nights. Also, Nights explanation tells me a little more on what I already knew about this.

Person person = *p1;
This is copying the pointer address to the first 4 bytes of firstName in the newly created instance of Person, and then completely undone by line 27:

Sorry, but that is actually not so. Person person = *p1; does a struct assignment, i.e. copying sizeof(Person) bytes over to the local destination struct person - hence yielding two identical, distinct person structs.

The following tries to demonstrate this behaviour ..

#include <stdio.h>
#include <string.h>
#undef NDEBUG
#include <assert.h>

typedef struct
{
  char firstName[50];
  char lastName[50];
  int age;
} Person;

int main()
{
  /* Three person structs ... */
  Person  John    = { "John", "Doe", 99 },
          clone_1 = { "?", "?", 1 },
          clone_2 = { "?", "?", 2 };

  /* A pointer to John */
  Person * ptr    = &John;

  /* Initial output */
  printf("%s\t%s\t%d\n", John.firstName, John.lastName, John.age);
  printf("%s\t%s\t%d\n", clone_1.firstName, clone_1.lastName, clone_1.age);
  printf("%s\t%s\t%d\n", clone_2.firstName, clone_2.lastName, clone_2.age);

  /* Clone John into clone_1, a struct assignment ... */
  clone_1 = John;

  /* The two structs are identical */
  assert(memcmp(&clone_1, &John, sizeof(Person)) == 0);

  /* Clone John into clone_2 dereferencing the pointer, effectively the same as above */
  clone_2 = *ptr;

  /* The two structs are identical */
  assert(memcmp(&clone_2, &John, sizeof(Person)) == 0);

  /* Final output */
  printf("%s\t%s\t%d\n", John.firstName, John.lastName, John.age);
  printf("%s\t%s\t%d\n", clone_1.firstName, clone_1.lastName, clone_1.age);
  printf("%s\t%s\t%d\n", clone_2.firstName, clone_2.lastName, clone_2.age);

  return 0;
}

/* Output ...
John    Doe     99
?       ?       1
?       ?       2
John    Doe     99
John    Doe     99
John    Doe     99
*/

Sorry, but that is actually not so. Person person = *p1; does a struct assignment, i.e. copying sizeof(Person) bytes over to the local destination struct person - hence yielding two identical, distinct person structs.

The following tries to demonstrate this behaviour ..

#include <stdio.h>
#include <string.h>
#undef NDEBUG
#include <assert.h>

typedef struct
{
  char firstName[50];
  char lastName[50];
  int age;
} Person;

int main()
{
  /* Three person structs ... */
  Person  John    = { "John", "Doe", 99 },
          clone_1 = { "?", "?", 1 },
          clone_2 = { "?", "?", 2 };

  /* A pointer to John */
  Person * ptr    = &John;

  /* Initial output */
  printf("%s\t%s\t%d\n", John.firstName, John.lastName, John.age);
  printf("%s\t%s\t%d\n", clone_1.firstName, clone_1.lastName, clone_1.age);
  printf("%s\t%s\t%d\n", clone_2.firstName, clone_2.lastName, clone_2.age);

  /* Clone John into clone_1, a struct assignment ... */
  clone_1 = John;

  /* The two structs are identical */
  assert(memcmp(&clone_1, &John, sizeof(Person)) == 0);

  /* Clone John into clone_2 dereferencing the pointer, effectively the same as above */
  clone_2 = *ptr;

  /* The two structs are identical */
  assert(memcmp(&clone_2, &John, sizeof(Person)) == 0);

  /* Final output */
  printf("%s\t%s\t%d\n", John.firstName, John.lastName, John.age);
  printf("%s\t%s\t%d\n", clone_1.firstName, clone_1.lastName, clone_1.age);
  printf("%s\t%s\t%d\n", clone_2.firstName, clone_2.lastName, clone_2.age);

  return 0;
}

/* Output ...
John    Doe     99
?       ?       1
?       ?       2
John    Doe     99
John    Doe     99
John    Doe     99
*/

Oops Yeah actually your right, the entire size is copied from the dereferenced value of *p1 into the newly created Person instance person, not its pointer. Not sure what I was thinking when I looked at that line.

But for the record, the 3 methods to access structure values from a pointer is correct.

Thanks for that catch mitrmkar!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.