Help Passing Struct Arrays to a function by value, not by reference.

Hello,

Sorry if this is in the wrong place.

I am working on incorporating a function in to an already existing piece of code, I have incorporated the function fine as far as I am aware.

The problem I have is that I am trying to pass two int arrays to the function, so that i can manipulate and compare them "the values will be changed the originals cannot be changed"

I am having trouble pulling the information out of the already created array, I am able to pass the pointer reference for the single value which is not exactly what i want "best_prog".


My function is below I have commented the memcpy parts and also the majority of the code isn't there cause it is not needed to see make the copy work.

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
int edit_distance(int index)
{
  struct prog *progp = &population[best_prog]; 

/* The struct of best prog not sure if i need one for the other prog I am trying to compare it with the one below doesn't work as intended.*/

  //struct prog *progp = &population[];

	int editdistance = 0, ar1 = 0, ar2 = 0, a = 0, b = 0, j = 0, x = 0;
	int i;

	int fittestprog[MAX_PROG_SIZE]={};	
	int compared_p[MAX_PROG_SIZE]={};
	int temp[MAX_PROG_SIZE]={};
	int ghost[1]={7};

	memcpy( (void *) &fittestprog[MAX_PROG_SIZE], (void *) &population[best_prog], MAX_PROG_SIZE); 

/*The first memcpy is to copy the best_prog which will be used in every case against the other index's of the main array the best_prog is determined by another function, I have been testing this and I am sure it just copies the pointer reference, I know that is what the & means but if i take it out the code wont work*/

	memcpy( &compared_p[MAX_PROG_SIZE], &population[index], MAX_PROG_SIZE);


/*The second memcpy is to copy a different index each time, the function is called. I cant even get the first index to copy across is it because i am calling it wrong with the parameters of the actual function.*/

//Below is just for testing where they correct things copied across.
	for( j = 0; j < 50 ; j++ )
			{
				printf("%d ", fittestprog[j]);
			}
	printf("\n\n");
		for( j = 0; j < 20 ; j++ )
			{
				printf("%d ", compared_p[j]);
			}
		printf("\n\n");
}


I have commented the bits I am stuck on below are the other function that involved with my function, such as where my function is called and where I am trying to pull the data from.

My Function Call
1
2
3
4
5
6
7
8
9
10
11
12
13
void display_stats(int gen)
{ int total_fitness = 0; int i, d; int deepest = 0;
  printf("GENERATION %d\n", gen);
  for (i =0; i < POPULATION_SIZE; i++)
  {  
   total_fitness += population[i].fitness;
  }
  int j = 0;
    for (j =0; j < 10; j++)
  {  
	edit_distance( j );
  }
}


Other functions that are used not in any specific order sorry.
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/* The population is what i need to transfer but only the best_prog from that population and other index everytime my function is called.*/

void initialise_population()
{
  struct prog *progp = population;
  int i, j, depth, full, attempts;
  char *end_tree;

  for (i = 2; i <= MAX_INIT_DEPTH; i++)
  {
     for (j = 0; j < PARTITION_SIZE; j++)
     {  depth = i; full = j%2; attempts=0;
        do
        {
           end_tree = create_tree(progp->code, depth, full);
           *end_tree = '\0';
           progp->proglen = strlen(progp->code);
           attempts++;
           if (attempts >= 5 && depth < MAX_INIT_DEPTH)
           { attempts = 0; depth++;
           }
        } while (duplicate(progp));
        progp++;
     }		
  }

  for (i=0; i < POPULATION_SIZE && !correct; i++)
     test_fitness(i);
}

// Enum tokens that convert to number to populate an array which would be just a string of numbers..
enum tokens {DUMMY, LEFT, RIGHT, MOVE, IF_FOOD_AHEAD, PROGN2, PROGN3};

struct token_entry
{
   char *name;
   int arity_sub1;
   // function
};

struct token_entry token_table [] =
     { {"# ", -1},     // String end. Arity must be -1 for sub-string search
       {"LEFT ", -1},
       {"RIGHT ", -1},
       {"MOVE ", -1},
       {"IF_FOOD_AHEAD ", 1},
       {"PROGN2 ", 1},
       {"PROGN3 ", 2},
	   //{"GHOST_NODE ", -1}
     };
//The arity is for comparing not really for what I need to figure out.


struct prog
{
  char code[MAX_PROG_SIZE+1];    // allow for string terminator
  int proglen;
  int fitness;
};


struct prog population [POPULATION_SIZE];

int best_prog;
int smallest_proglen;
int best_fitness;

//Testing fitness is to determine the best prog for its generation, I used similar technique of memcpy to try and get the values into my function, the pellets are to do with a matrix map that has no real value to me.
void test_fitness(int index)
{
  // Evaluate fitness of the indexed individual

  struct prog *progp = &population[index];
  int count = progp->proglen;

  // Initialise the trail matrix
  memcpy(matrix, matrix_data, MATRIX_SIZE*MATRIX_SIZE);
  pellets = NUM_PELLETS;

  if (trace)
     memcpy(trace_matrix, matrix_data, MATRIX_SIZE*MATRIX_SIZE);

  // Position the ant
  row = 0; col = 0; heading = EAST; steps = 0;

  // Repeatedly evaluate tree until all pellets eaten or we time out
  do
  {  nodep = progp->code;
     evaltree();
  }  while (pellets > 0 && steps < MAX_STEPS);

  correct = (pellets == 0);
  progp->fitness = pellets;

  if (pellets < best_fitness ||
     (pellets == best_fitness && count < smallest_proglen))
  {  best_prog = index;
     best_fitness = pellets;
     smallest_proglen = count;
  }
}


I know its a long post but I needed to explain it first, any help would be greatly appreciated seen as I am quite stuck on this matter, I did research passing by value but I didn't have much luck and couldn't find the answer i needed.

Thank you
Last edited on
memcpy( (void *) &fittestprog[MAX_PROG_SIZE], (void *) &population[best_prog], MAX_PROG_SIZE);

fittestprog[MAX_PROG_SIZE] is an element that is out of the bounds of the fittestprog array. The same is true of compared_p on line21 of the first code snippet.

You are taking the address of that non-existent element and feeding it to memcpy as the start of an area of memory to write to. Not good -- you're clobbering memory you don't own.

It would appear that the type held by population is a structure type that is much larger than an int, but you seem to be treating them via memcpy as if the elements are the same type. Also, the last parameter memcpy takes is the number of bytes to copy, so MAX_PROG_SIZE is almost certainly wrong in any case.
What would be the better way of representing and not using up so much memory.

Also completely forgot to put the defines in sorry.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <malloc.h>
#include <conio.h>
#include <string.h>


#define MAXINT INT_MAX
#define POPULATION_SIZE  500
#define PARTITION_SIZE   (POPULATION_SIZE/(MAX_INIT_DEPTH - 1))
// Need to ensure that pop. size is a precise multiple of (MAX_INIT_DEPTH-1)

#define PCROSS           0.818
#define PROB_TERM        0.1
#define MAX_GEN          50
#define TOURN_SIZE       5
#define MAX_PROG_SIZE    1000
#define MAX_PROG_OVERFLOW	2000
#define NUM_RUNS         100
#define TRUE             1
#define FALSE            0 


How would i go about fixing the problem, sorry im quite new to this still.
Can you explain what fittestprog and compared_p should contain after the memcpys in your current code? Not necessarily in the problem domain. But, what values stored in population should be present in them?
Fittest_prog need to contain the best_prog from the population the population is made up of an array of string ints such as

for a very small example 2 of the strings "below" would be something like this obviously they would be a lot large strings "up to 1000", the numbers represent enum tokens which all stand for something specific.

before memcpy

best_prog_example{4, 5, 1, 6, 1, 2, 3, 3};
Some index of the population_example{5, 1, 5, 2, 5, 4, 3, 1, 3};

after memcpy
int fittestprog[MAX_PROG_SIZE]={4, 5, 1, 6, 1, 2, 3, 3};
int compared_p[MAX_PROG_SIZE]={5, 1, 5, 2, 5, 4, 3, 1, 3};

Basically i just need a copy of the original population index, although i wish it was that simple.

Anyway the population contains 500 of these string arrays of ints and i take 2, one being the fittest_prog also known as the best_prog and another is just one of the population of 500.

All the 500 arrays need to be compared against the best_prog so i need to pass the into my function where i can manipulate and compare them.

Unfortunately this is the first time i have worked with C++ and I am rather lost. the rest of my function is actually done I am happy to show you any bits of the code you require just its rather long for a forum post.

And not sure it would help.

enum tokens {DUMMY, LEFT, RIGHT, MOVE, IF_FOOD_AHEAD, PROGN2, PROGN3};

These are what the number represent dummy is just 0

left = 1
right = 2
move = 3
if_food_ahead = 4
progn2 = 5
progn3 = 6

Really appreciate that you are trying to help and understand, thank you.
Last edited on
If I understand correctly:

1
2
3
4
5
6
7
8
9
10
11
12
13
int edit_distance(int index)
{
    struct prog *progp = &population[best_prog]; 

    int editdistance = 0, ar1 = 0, ar2 = 0, a = 0, b = 0, j = 0, x = 0;
    int i;

    char fittestprog[MAX_PROG_SIZE] = {} ;
    char compared_p[MAX_PROG_SIZE] = {} ;

    memcpy( fittestprog, population[best_prog].code, MAX_PROG_SIZE ) ;
    memcpy( compared_p, population[index].code, MAX_PROG_SIZE) ;
    // ... 


There may be issues depending on how you're using this information and whether population[i].code is actually in c-string form or not. It may be that the values are stored as '1', '2', etc. instead of as the actual values, in which case you may need to convert them if you want to deal with the actual values. Just something to keep in mind.


Unfortunately this is the first time i have worked with C++ and I am rather lost.

This looks like pure C to me.
Last edited on
Just going to implement it and run a few tests, this is the first time i have used C/C++ its a .cpp file so I assume it was c++

So far its printing out the best prog okay, I think.

The values are fine as ints because that's what i need to work with. so how does the .code work ? i saw it previously in the other functions but didn't get how ti was referencing exactly.
After running a few tests and calculating the output I noticed that its the first for loop it is printing out the best prog which is great but after it has reached the best_progs max length it then prints out which i assume is the next prog at least its a completely different set of numbers.

Would this be because of the max_prog_size should i be changing this to 8 for the byte value although I am unsure if that would be correct.

The second for loop is not working yet I think it is because i haven't included the struct for the index like i did best_best.

But i know when i tried last time i got an initialisation error

struct prog *progp = &population[index];

will try and recreate the error
I did some more tests apparently when the the mmcpy copies over using MAX_PROG_SIZE it copies everything up to the size of max prog size which isn't good i looked at the initialise population function and proglen is declared but not sure how to use it in the memcopy function because i didn't really understand it.

also if i include the extra line below

struct prog *progp = &population[index];

The error appears

1
2
3
4
5

antsimple.cpp
antsimple.cpp(485) : error C2374: 'progp' : redefinition; multiple initializatio
n
        antsimple.cpp(484) : see declaration of 'progp'


I know its trying to re-declare it and not sure i want that.

Thank you for your help so far, i will keep trying to understand it.
I did some more tests apparently when the the mmcpy copies over using MAX_PROG_SIZE it copies everything up to the size of max prog size which isn't good i looked at the initialise population function and proglen is declared but not sure how to use it in the memcopy function because i didn't really understand it.


1
2
    memcpy( fittestprog, population[best_prog].code, population[best_prog].proglen ) ;
    memcpy( compared_p, population[index].code, population[index].proglen ) ;


It may be better to just copy the entire prog objects as opposed to just the "code."


Just going to implement it and run a few tests, this is the first time i have used C/C++ its a .cpp file so I assume it was c++

It's pure C that was thrown into a C++ source file. Not exactly great C, either.


so how does the .code work ?

Each prog object has 3 members. In order to access a member of a prog object you use the . operator: population[index].code. When you use the name of an array with no subscripts, in many contexts it is interpreted as a pointer to the first element, which is why there is no need to use the address of operator (&) in the above code.

Of course, if you're using a pointer to an object one uses the -> operator to accomplish the same thing.

1
2
3
4
5
6
7
8
9
    prog* p = population ;

    p->code ;
    // is equivalent to:
    (*p).code ;

    p[0].code ;
    // is equivalent to:
    (p+0)->code



prog* p = population; p->code is the same thing as population[0].code

[edit: oops. Made an edit to the code at the top. Used best_prog where index should've been used.]
Last edited on
My bit is the edit_distance function the rest is not mine. Hence why i am having such trouble, hardly any comments to explain it all too.

+Seen as im so new im sorry if the coding is bad.

Anyway I am very grateful for the help, i implemented the memcpy it works great for the best_prog which is fine I tried to get the other memcpy to work but seems like the index isn't linking at all i looked at the parameters i was passing but i had no luck.

The proglen operator worked like a charm although i changed the second line proglen operator to index seen as i dont want to call the length of the best prog when it gets calculated.

1
2
 memcpy( fittestprog, population[best_prog].code, population[best_prog].proglen ) ;
    memcpy( compared_p, population[index].code, population[index].proglen ) ;


I was looking at where I am calling the actual function i dont think i am passing the correct argument, seen as i was going to call it multiple times increasing the value i was passing I thought in theory it would use that value for the index, please tell em if im completely wrong here.

Also would it be possible to call the struct for just normal index like i did for the best_prog something like although i know its wrong

struct prog *progp = &population[index];

Or would it be better to put that in function parameters?

Sorry for a lot of noob questions.
The proglen operator worked like a charm although i changed the second line proglen operator to index seen as i dont want to call the length of the best prog when it gets calculated.

Yep. I corrected the code shortly after I posted it.

I was looking at where I am calling the actual function i dont think i am passing the correct argument, seen as i was going to call it multiple times increasing the value i was passing I thought in theory it would use that value for the index, please tell em if im completely wrong here

If you're talking about where it is called in display_stats, that is exactly what happens. edit_distance will be called 10 times with index set to 0 through 9.


Also would it be possible to call the struct for just normal index like i did for the best_prog something like although i know its wrong

struct prog *progp = &population[index];

Or would it be better to put that in function parameters?

If you're talking about making index a global variable, it's certainly doable. Not good practice, though; better to leave it an argument to the function.
Sorry for late reply, yes that is perfect, really appreciate the help. Never knew about the .operator really appreciate it.

Wade
Topic archived. No new replies allowed.