C prog: printing values from array of structures

In summary: When you pass them by value you will not pass a pointer to an array, you will pass an individual object (note: object is bad choice of word :P). The only way this can be achieved is by calling the function print_names as many times as the array is large.
  • #1
Math Is Hard
Staff Emeritus
Science Advisor
Gold Member
4,652
37
Hello, I have a little function I have written that takes an array of structures as an argument

PHP:
void print_names(struct pers_info arr[])
{
  printf("Here is person 1: %d %s %s %s\n", arr[0].ssn, 
    arr[0].pers_name.first,arr[0].pers_name.middle, arr[0].pers_name.last);
  printf("Here is person 2: %d %s %s %s\n", arr[1].ssn, 
    arr[1].pers_name.first,arr[1].pers_name.middle, arr[1].pers_name.last);
}
This is working fine - it prints a number, then a first name, middle name, and last name. The problem is that when I print the middle name I only want to print the first initial. I can't figure out how to print only the first character of the pers_name.middle character string. Thanks for your help.
 
Computer science news on Phys.org
  • #2
Try this:

Code:
printf("%c",arr[0].pers_name.middle[0]);

A string is just a character array.
 
  • #3
Thanks! That did the trick!
 
  • #4
You can also give the string conversion maximum number of characters. (Though this is obviously more useful for numbers greater than 1...)

PHP:
printf("%.1s",arr[0].pers_name.middle);
 
Last edited:
  • #5
hey there plover. You know, that was my first thought- that I would do some kind of a truncation thingy when I did the specifications. But I figure he wants to see us specifically access the character in the array, so I went with that.
I am doing some alterations now to make the print function loop through all the elements in the structure array and print it one way if a middle name is found and another way if a middle name is not found. I'm not quite sure if that's the most elegant way to handle it but I'll see how it comes out and if it starts looking clunky I'll post again.
 
  • #6
well, I got the first part of the assignment taken care of which was to pass the structure array to my printing function. At least I think I handled it right. I called the function like this:
PHP:
print_names(arr);
and then wrote my function heading like this:
PHP:
void print_names(struct pers_info arr[])

now, the second part of the assignment asks me to go back and modify the program by passing the structure value instead of the address this time.
I am getting confused here. Is he asking me to pass individual elements of the structure maybe?
:confused:
Thanks.
 
  • #7
How would you set up the function so that this call made sense?

PHP:
print_name(arr[n]);

What would happen when the function was called?
 
  • #8
well, I'm not sure. maybe I should create an argument for the number of elements in the array? like...

void print_names(struct pers_info arr[], int n)
 
  • #9
Are you familiar with pointers? if so the following statements are equivalent

Code:
arr[];
*arr;

When you pass them by value you will not pass a pointer to an array, you will pass an individual object (note: object is bad choice of word :P). The only way this can be achieved is by calling the function print_names as many times as the array is large.

Just as plover was hinting at you want to do this:
Code:
int n=0;
for (n=0;n<size;n++){
print_names(arr[n]);
}

You should also re-write your function above to be the same thing but instead pass a reference to the object, kinda like

Code:
print_names(&arr[n]); //you could ultimately do it other ways, but this is conceptually simple
//on the function prototype you would need to use a * to let the compiler know that an address was being passed.

Otherwise you would have to add the size parameter as you thought of above.
 
  • #10
Goalie_Ca said:
When you pass them by value you will not pass a pointer to an array, you will pass an individual object (note: object is bad choice of word :P). The only way this can be achieved is by calling the function print_names as many times as the array is large.

Just as plover was hinting at you want to do this:
Code:
int n=0;
for (n=0;n<size;n++){
print_names(arr[n]);
}

hmmmm...In my current version I have a loop that sort of does that. I give it an array of structure addresses, and I display the structure contents

PHP:
void print_names(struct pers_info arr[])
{
  int i;
  for (i=0;i<5;i++)	
  {
    if (arr[i].pers_name.middle[i] == '\0') //no middle initial
    {
      printf("%s, %s -- %d \n",  arr[i].pers_name.last, arr[i].pers_name.first,
      arr[i].ssn);
    }
   else  //if there is a middle initial
    {
      printf("%s, %s %c. -- %d \n",  arr[i].pers_name.last, 
      arr[i].pers_name.first, arr[i].pers_name.middle[0],arr[i].ssn);
    }
  }
}

You should also re-write your function above to be the same thing but instead pass a reference to the object, kinda like

Code:
print_names(&arr[n]); //you could ultimately do it other ways, but this is conceptually simple
//on the function prototype you would need to use a * to let the compiler know that an address was being passed.

Otherwise you would have to add the size parameter as you thought of above.

Can I keep what's inside my printing function as is but just pass
&arr to it to specify that the value should be passed rather that the address?

Thanks.
 
  • #11
C uses a method called pass-by-value when sending arguments to a function. So, if you a have a function:
PHP:
void uselessFunc(int n) { n += 1; }
and later have the instructions:
PHP:
int a = 100;
uselessFunc(a);
printf("%d\n", a);
the number printed will be 100, as the value of a is copied to the argument n (i.e. passed by value). Thus any operations on n do not affect a. This is why you pass a pointer when you want to affect the original object, because then it is the address that is value that gets copied, and a copy of the address will, of course, still de-reference to the original object.

The same principle works if the argument is a struct rather than just an int.

Do the questions in my previous post make more sense with this to go with them? (Also note that my function was called print_name rather than print_names.)

It seems slightly strange to me that the teacher would imply that both of the functions you're asked to write would be able to work on the entire array at once, but perhaps I am misunderstanding something in your description.

The follow-up that Goalie_Ca gave to my hint is correct, and in most situations his advice to pass the address would be good. However, from what I can tell of your instructions, you are being asked to not pass the address here.

I should probably point out that I am assuming you've seen these ideas before. I'm just trying to show the context from which the problem can be answered.

(I hope I'm not being too oblique. You should tell me if I'm just confusing you more than helping...)
 
  • #12
I think I am understanding now. The difference is just between passing the pointer address and passing the value that is being pointed to.
It seems slightly strange to me that the teacher would imply that both of the functions you're asked to write would be able to work on the entire array at once, but perhaps I am misunderstanding something in your description.
No, I think he is just asking for two different versions of the same program.
I actually hadn't heard the term "pass by value" method before. I think initially that is all we were doing but it didn't have a special name. I get confused I think because I don't know how much the rules change (if at all) when I am working with a structure.
And I do appreciate the help. Sorry I am not absorbing the info faster. Maybe I shoud work on a smaller simpler version of what I am trying to do and then try to apply it back to my program. Just so I'll know how to use pass by value in this case.
 
  • #13
I made up a simpler example to see if I can get my head around this. I just have a character array and I am passing a pointer to it. Maybe someone could show me how to write this using Pass By Value? Thanks. :smile:

PHP:
#include <stdio.h>
int main(void)
{
void print_array(char * a); //proto

char arr[3] = {'A','B','C'};

print_array(arr); //call printing function	
return 0;
}

void print_array(char * a)
{
	int i;
	for (i=0;i<3;i++)
	{
		printf("%c \n",a[i]);
	}
}
 
  • #14
You cannot pass an array by value. An array is actually a pointer to a memory block. When you do array[3] you are essentially adding 3*data_size to the array starting address. Mmmkay.. You have to move that for loop outside the function.

Code:
#include <stdio.h> 
void print_array(char a); //proto 


int main(void) 
{ 
char arr[3] = {'A','B','C'}; 
int n=0;
for (n=0;n<3;n++)
    print_array(arr[n]); // equivalent to *(arr+3)**** 
return 0; 
} 

void print_array(char a) 
{ 
********printf("%c \n",a);  
}
 
  • #15
Goalie - thank you. I remembered from examples that for arrays we had to specifically pass a pointer to a function but I was getting a little muddled on why that was.
So you are saying use the loop to grab the value first and then pass the value off to the printing function I think? uh.. I hope I understood that..
Anyway, I appreciate your explanations and your patience.
 
  • #16
'Pass-by-value' is not something the programmer does -- it is built into the C language. It is the method that C programs use to pass arguments to functions. (The other common method is pass-by-reference, where the function argument assumes the identity of the variable that is passed in instead of copying it. C++ uses both methods.)

Suppose you have a struct:
PHP:
struct point2d { 
    double x;
    double y;
} targetCoord;
and a function with the prototype:
PHP:
int swatFly(int id, struct point2d target);
At some point in the code you have:
PHP:
int flyId = 666;
targetCoord.x = 3.1415;
targetCoord.y = 2.7183;
int isFlyToast = swatFly(flyId, targetCoord);

When you call swatFly, what happens? The system sets up the memory space necessary to execute a function (it's called a stack-frame -- if that's meaningless to you, don't worry about it). Included in that memory space will be spots for all of the arguments and local variables used by the function. Since C uses call-by-value, it then looks at the value of 'flyId' and copies that value to the address that will be used by the parameter 'id'. Then it looks at 'targetCoord' and copies the value of that to 'target'; since the system has already seen the definition of 'point2d', it knows that this value is two items of type 'double'.

The slightly confusing case is arrays. If you have an array A, then an item in that array A[n] acts just like any other variable of whatever type is stored in A. But what does the symbol 'A' by itself mean? In most circumstances, the most useful meaning is to say where the array A is. So the symbol A is interpreted as the address of the first item in the array (another way to say this would be that the array is converted to a pointer). Thus when an array is passed to a function, the value that is copied by the 'pass-by-value' mechanism is the address. (The prototype of the function can specify either an array or a pointer in these cases.)

I am glossing over a few things, but I hope this is enough information to clarify the current problem.
 
  • #17
plover, that is very interesting - thank you. Tell me, why is targetCoord outside of the structure in

struct point2d {
double x;
double y;
} targetCoord;

and the other thing I am not sure about (just occurred to me) is what the & symbol does here in the post by Goalie
print_names(&arr[n]);

Thanks rain-bird friend! :smile:
 
  • #18
I'm sorry, I didn't know you hadn't seen this syntax. It is possible to include variable declarations along with the definition of a struct. Thus, targetCoord is just being declared as a variable of type struct point2d.

In &arr[n], the '&' means "take the address of". Thus, &arr[n] passes a pointer to the array element, where arr[n] would pass the array element itself. For a large struct, you usually want to pass the pointer as that is much more efficient than copying the whole struct.
 
  • #19
plover said:
I'm sorry, I didn't know you hadn't seen this syntax. It is possible to include variable declarations along with the definition of a struct. Thus, targetCoord is just being declared as a variable of type struct point2d.

ahhh... I see!

In &arr[n], the '&' means "take the address of". Thus, &arr[n] passes a pointer to the array element, where arr[n] would pass the array element itself. For a large struct, you usually want to pass the pointer as that is much more efficient than copying the whole struct.

Thanks. I was thinking it had something to do with the address because I had seen it used when assigning an address to a pointer like

MyPointer = &Fred;

to assign the address of Fred to MyPointer. But I was surprised to see it used as part of a parameter in a function call.

Let me see if I understand. I am still not sure I have grasped it, so I will state my interpretation and you'll be able to see my thought processes on this and where I might be having trouble:

Using this as a parameter in a function call passes a pointer to the nth element of the array
&arr[n]
in other words, the address of the nth element in the array.

Using this as a parameter in a function call passes the value stored at the nth position in the array:
arr[n]
for instance if arr was a char array it would pass an actual character like 'A' or 'j'. It would behave the same as if you were passing over a single char variable even though it is actually a member of an array.

Thanks. :smile:
 
  • #20
Here's something else for you to think of, if you understand this then you have a decent idea of pointers...



char arr[3][2];

what would arr pass?
what would arr[2] pass?
what would arr[2][1] pass?

One other thing, you can also have function pointers, void pointers, and others.
 
Last edited:
  • #21
hmm.. I think arr is an array of 3 pointers to arrays of two characters each.

Did I understand that much?
 
  • #22
what would arr pass?
I think this would pass the address of the first element in the array of pointers called arr. (i.e. it's passing an address)

what would arr[2] pass?
I think this would pass the address of the third element in the array of pointers called arr (i.e. it's passing an address)

what would arr[2][1] pass?
I think this would pass the value of the second character stored in the third character array? I am visualizing it kinda like this
PHP:
==========================================================
        arr[0]      |     arr[1]          |     arr[2] 
==========================================================
1st char| 2nd char  |  1st char| 2nd char |1st char| 2nd char 
==========================================================

(sorry- I tried my best to draw a picture)

but I don't know if that's right.
 
  • #23
As far as it goes, you've got the right idea. The question now is: what does the parameter type have to be in each case for the argument to be accepted?
 
  • #24
uhhh... pointer, pointer, and char respectively?
 
  • #25
The third one is char, of course. But 'arr' and 'arr[2]' do not have identical pointer types. E.g. 'arr' and 'arr[0]' may indicate the same address, but '(arr + 1)' and '(arr[0] + 1)' do not.

Note that a compiler may let you use them interchangeably (though it should at least spit out a warning), but doing so will get you in trouble if you don't know precisely what is going on (and is not good programming practice anyway).
 
  • #26
still stuck

I don't think I am passing it the character from the structures the right way. I still can't get this to work. Here's the whole enchilada.
Take a look? Thanks...

PHP:
#include <stdio.h>
# define LEN 35

void print_names(char a); //prototype of printing function

struct name  // defines the name structure
{
	char first[LEN];
	char middle [LEN];
	char last[LEN];
};

struct pers_info //defines the personal info structure
{
char ssn[10];
struct name pers_name;
};

int main(void)
{
	//create and init array of pers_info structures
struct pers_info arr[5] = 
{
	{
	"123456123", {"Anne","Appleby","Adams"}
	},
	{
	"623001200", {"Bud", "","Burke"}
	},
	{
	"423456999", {"Carol","","Cooper"}
	},
	{
	"327856909", {"Darryl","Dimitri","Dodd"}
	},
	{
	"563456929", {"Evelyn","Elizabeth","Eggwhite"}
	}

};

int n=0;
for (n=0;n<5;n++)
print_names(struct pers_info arr[n]);	
return 0;
}

void print_names(char a)
{
	printf("%c \n", a);
}

All this is supposed to do is print names and social security numbers.
 
Last edited:
  • #27
should I be passing strings? or can I even do that?
 
  • #28
It doesn't even look like this will compile:

print_names(struct pers_info arr[n]);

- Warren
 
  • #29
no - it won't - it's a mess
 
  • #30
This is the version I wrote that works - but it doesn't pass values: :frown:

PHP:
#include <stdio.h>
# define LEN 35

void print_names(struct pers_info arr[]); //prototype of printing function

struct name  // defines the name structure
{
	char first[LEN];
	char middle [LEN];
	char last[LEN];
};

struct pers_info //defines the personal info structure
{
int ssn;
struct name pers_name;
};

int main(void)
{
	//create and init array of pers_info structures
struct pers_info arr[5] = 
{
	{
	123456123, {"Anne","Appleby","Adams"}
	},
	{
	623001200, {"Bud", "","Burke"}
	},
	{
	423456999, {"Carol","","Cooper"}
	},
	{
	327856909, {"Darryl","Dimitri","Dodd"}
	},
	{
	563456929, {"Evelyn","Elizabeth","Eggwhite"}
	}

};

print_names(arr); //call printing function	
return 0;
}

void print_names(struct pers_info arr[])
{
int i;

	for (i=0;i<5;i++)
	{
		if (arr[i].pers_name.middle[i] == '\0') //no middle initial
		{
			printf("%s, %s -- %d \n",  arr[i].pers_name.last, arr[i].pers_name.first,arr[i].ssn);
		}
		else  //if there is a middle initial
		{
			printf("%s, %s %c. -- %d \n",  arr[i].pers_name.last, arr[i].pers_name.first,
				arr[i].pers_name.middle[0],arr[i].ssn);
		}
	}
}
 
  • #31
Your function should look like this:

PHP:
void print_name(struct pers_info record) {
    ...
}

And the code calling it should look like:

PHP:
for (int n=0;n<5;n++)
   print_name(arr[n]);

Passing a struct by value is no different than passing any other kind of variable by value.

- Warren
 
  • #32
print_names(struct pers_info arr[n]);

You don't need to include the type when passing an argument (except for type casts, which is not what's required here).
 
  • #33
chroot said:
Your function should look like this:

PHP:
void print_name(struct pers_info record) {
    ...
}
record? Does that mean one of the individual structures I made? thanks. Record isn't a keyword is it?
 
  • #34
record is a keyword in Pascal (I think), not in C though.

In chroot's example, it's just the name of the argument.
 
  • #35
When you create a function, you can call the variables it receives by any names you'd like. Even if the calling function referred to a hunk of data as arr[n], the called function can choose to call that incoming hunk of data anything it wants. In this case, I chose the word 'record' to refer to the variable being passed into the print_name function. It's not a reserved word in C, and means, well, nothing -- you can call it aStudent if you want, or theThingy, too.

- Warren
 

Similar threads

  • Engineering and Comp Sci Homework Help
Replies
3
Views
743
  • Programming and Computer Science
Replies
29
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
4
Views
918
  • Engineering and Comp Sci Homework Help
Replies
18
Views
1K
  • Programming and Computer Science
Replies
9
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
1K
  • Programming and Computer Science
Replies
22
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
21
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
1K
Back
Top