Problem with modifying array argument in function

Dec 19, 2015 at 8:55pm
Hello everyone!
I've got some experience with Java and C, but I'm very new to C++. Therefore, I guess the answer to my question will be obvious, but I just can't figure it out on my own.

I've got the following code:

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
#include <gmp.h>
#include <flint.h>
#include <fmpz.h>
#include <fmpz_poly.h>
#include <iostream>

using namespace std;

template<int length>

void random_code(fmpz_t (&result)[length]) {
	for(int i=0; i<length; i++) {
		fmpz_set_ui(result[i], 1); //not quite random, but for now it will do
	}
}

int main() {
	int len = 4;
	fmpz_t test[len];
	for(int i=0; i<len; i++) {
		fmpz_init(test[i]);
	}
	random_code(test);
	cout << "value of test: ";
	for(int i=0; i<len; i++) {
		fmpz_print(test[i]);
	}
	cout << endl;

	return 0;
}


I want to initialize an array of fmpz_t's and then set each component in the array to a certain value. The problem is that I want to modify the array argument in random_code, so I made the argument a reference to that array, but it doesn't seem to work.

When I try to compile it, I get the following error and notes:

gen_code.cpp: In function 'int main()':
gen_code.cpp:23:18: error: no matching function for call to 'random_code(fmpz [len][1])'
random_code(test);

gen_code.cpp:11:6 note: candidate: template<int length> void random_code(fmpz (&)[length][1])
void random_code(fmpz_t (&result)[length]) {

gen_code.cpp:11:6: note: template argument deduction/substitution failed:
gen_code.cpp:23:18: note: variable-sized array type 'int' is not a valid template argument
random_code(test);

I know that there is something wrong with the line 'random_code(test)' in main() and that I don't call the argument correctly, but I just don't see the solution, so I hope there's someone who can help me. Thanks in advance!
Dec 19, 2015 at 9:35pm
I just threw this together to get it to compile and run.
The typedef was just a temporary workaround, you don't need that.
Note len in main() must be const.

The function bodies at lines 7, 8 and 9 are just random nonsense I made up, again to get it to compile and link.

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
#include <iostream>

using namespace std;

typedef int fmpz_t;

void fmpz_set_ui(fmpz_t & a, int b ) { a = b; }
void fmpz_init(fmpz_t & a) { a = 0; }
void fmpz_print(fmpz_t a) { std::cout << a << ' '; }

void random_code(fmpz_t result[], int length) {
    for(int i=0; i<length; i++) {
        fmpz_set_ui(result[i], 1); //not quite random, but for now it will do
    }
}

int main() 
{
    const int len = 4;
    fmpz_t test[len];
	
    for (int i=0; i<len; i++) {
        fmpz_init(test[i]);
    }
	
    random_code(test, len);
	
    cout << "value of test: ";
    for (int i=0; i<len; i++) {
        fmpz_print(test[i]);
    }
    cout << endl;

    return 0;
}
Last edited on Dec 19, 2015 at 10:06pm
Dec 21, 2015 at 10:34am
Thanks a lot, it works!! But I'm a bit confused now, because I searched on Google and I learned that when you want to modify an argument of a function inside the body of that function, you should put the reference to that argument in the function (i.e. & before the argument). But now you didn't and it still works. Could you perhaps explain me that?
Dec 21, 2015 at 11:11am
My code does use references in
7
8
void fmpz_set_ui(fmpz_t & a, int b ) { a = b; }
void fmpz_init(fmpz_t & a) { a = 0; }


At line 11,
 
void random_code(fmpz_t result[], int length) {

When an array is passed as a parameter to a function, it actually passes the address of the first element of the array. See "Arrays as parameters" in the tutorial.
http://www.cplusplus.com/doc/tutorial/arrays/
Dec 21, 2015 at 12:58pm
Thanks for your answer! But the library fmpz doesn't use references in those functions, unlike your implementation of the functions.
Dec 21, 2015 at 1:30pm
Well, I had no idea what the functions fmpz_set_ui() and fmpz_init() were supposed to do, I've no idea what type of animal a fmpz represents. I just wrote some code which would compile and run, that's all.

edit:
A bit of googling, it looks like type fmpz_t is actually a typdef of a pointer type, thus it uses a pointer rather than a reference.
Last edited on Dec 21, 2015 at 2:46pm
Dec 23, 2015 at 10:38am
Thanks for your help!! I've got one last question. I'm not completely comfortable with pointers and references yet, especially not in the case of arrays. Does the fact that fmpz_t uses a pointer rather than a reference mean that I have to change anything to the code? The function random_code now looks like this:

 
void random_code(fmpz_t result[], size_t length) {


I mean, it works, but as I learned to use references when modifying an argument in a function, I'm still a bit confused.
Dec 23, 2015 at 4:00pm
I would think your code is fine as it stands now,

Pointers and references are loosely related. They are not the same thing. But both of them allow a function to change the contents of a parameter.

Consider the following example. I tried to keep it as simple as possible.

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
#include <iostream>

using namespace std;

void changex(int x)
{
    x = x + 1;
}

void changey(int* y)
{
    *y = *y + 1;
}

void changez(int &z)
{
    z = z + 1;
}

int main()
{
    int x = 5;
    int y = 5;
    int z = 5;

    changex(x);    // x is passed by value
    changey(&y);   // address of y is passed
    changez(z);    // z is passed by reference

    cout << "x: " << x << "    y: " << y << "    z: " << z << '\n';
  
    return 0;
}

x: 5    y: 6    z: 6


1. changex(int x) This example fails to work. Depending on the compiler, there may be a warning message, mine gives 'x' is assigned a value that is never used at line 7. The variable x is a local variable which exists only for the lifetime of the function. Its value is a copy of the parameter given when the function is called

2. changey(int* y) y is a pointer. When the function is called, the parameter must be a pointer. Notice also within the function the pointer must be dereferenced to access the thing which is pointed to.

3. changez(int &z) Often this is the preferred approach. z is passed by reference. This means that in effect the variable z inside the function is the same object as that in the calling code (though it need not have the same name).
Dec 23, 2015 at 4:14pm
As for arrays and pointers, when passing an array to a function, it is the address of the array start which is passed, and though an array is not the same thing as a pointer, they have similarities:
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
#include <iostream>

using namespace std;

void func1(char * str)
{
    *str = 'L';
}

void func2(char str[])
{
    str[0] = 'B';
}

int main()
{
    char word1[] = "dog";
    char word2[] = "cat";

    func1(word1);
    func2(word2);

    cout << "word1: " << word1 << '\n';
    cout << "word2: " << word2 << '\n';
}

word1: Log
word2: Bat
Dec 23, 2015 at 8:59pm
Thanks a lot for your explanation Chervil!!! I think I understand it better now.
Dec 23, 2015 at 10:03pm
Your first program was perfectly fine, it has only one error, at line 18:
1
2
	int len = 4; // len is not const, cannot be used as array size
	fmpz_t test[len]; // error here 

which should have said
1
2
	const int len = 4; // this fixes everything
	fmpz_t test[len]; 


Your first random_code actually passed the array by reference and it's a good thing to know how to do that since pointer and size is pretty much the worst possible interface a function that works on an array can have. (array by reference isn't perfect either, the best interfaces are iterator pair and array view - see ISO C++ Core Guidelines item I.13: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#-i13-do-not-pass-an-array-as-a-single-pointer
Last edited on Dec 23, 2015 at 10:05pm
Topic archived. No new replies allowed.