Defining global multidimensional arrays with extern const Length: segfault

I need to have a few global variables accessible by multiple files.
I am having a segfault. I have managed to create a small program exhibiting this error.

file global.h:
1
2
3
4
5
6
7
8
#ifndef GUARD_Global_Defs
#define GUARD_Global_Defs

extern const int L ;

extern double  ** grows;

#endif 


file global.cpp
1
2
extern const int L = 3;
double grows[2][L +1];


file test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "global.h"
#include  <iostream>
#include <string>

using namespace std;

int main(){
  double val;

  for(int i=0; i<L-1; i++){
    val = grows[1][i];
    cout << val <<endl;
  }

  return 0;
}

g++ -Wall -Wextra -std=c++11 -c global.cpp
g++ -Wall -Wextra -std=c++11 global.o test.cpp -o test

When I run it, I get a segfault.
Why? And how can I fix it?
What do you expect to happen when you use incompatible types?

http://ideone.com/wfRIoR

int ** and int[x][y] are unrelated types.
Last edited on
Ah. It compiled, so I thought the types were compatible.

And the reason why I have extern double ** grows in the header is that if I try
extern double grows[2][L +1]; the compiler complains that the array dimension is not a constant something something.

So, what should the header global.h be?

Thanks!
The size of an array must be known at compile time. Not link time. That means the size has to be in the same file as the array, and has to be defined before the array.
Yes, I get that. But how does one solve the problem of having one global array
double grows[2][L +1], where L is a const, that is available to several program files?

For one dimensional arrays, I can define it like
double gone_dim[L ] in one file (with L defined in the same file), declare it in a separate .h files as extern double gone_dim[], and things work out.

For two dim arrays this strategy does not work -- I can define it fine, but I don't know how to declare it. In the original program files in the first post, I cannot do something like:
1
2
3
4
5
6
7
8
#ifndef GUARD_Global_Defs
#define GUARD_Global_Defs

extern const int L ;

extern double  grows[2][L+1];

#endif  

The compiler complains that the array dimension is not a constant.

Is this a case where L should be defined using a #define?
First array dimension might be unknown in compile time in declaration. That way it will decay to pointer: your double gone_dim[]; is actually double* gone_dim; — it is not actual array and many function expecting array will not work with it (std::begin for exmple).

Two dimensional arrays can be declare with first dimension unknown in compile time:
1
2
3
extern double a[5][5]; //Correct
extern double b[4][ ]; //Error
extern double c[ ][3]; //Correct. c is actually double (*)[3] — pointer to array, not array of arrays 
> extern double c[ ][3]; //Correct. c is actually double (*)[3] — pointer to array, not array of arrays

c is actually an array of unknown size (and not a pointer to array).
At this point, the type is an incomplete type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <type_traits>

extern double c[][3]; // the (incomplete) type of c is array of unknown size of int[3] 
extern const std::size_t sz ;

int main()
{
    static_assert( !std::is_same< decltype(c), double (*)[3] >::value, "can't be the same type" ) ;
    static_assert( std::is_array< decltype(c) >::value, "must be an array type" ) ;
    static_assert( !std::is_pointer< decltype(c) >::value, "can't be a pointer" ) ;
    
    // std::cout << sizeof(c) << '\n' ; // *** error: size of incomplete type
    std::cout << "sz: "  << sz << '\n' ; // fine
}

double c[100][3]{}; // the (complete) type of c is array of 100 int[3] 

const std::size_t sz = sizeof(c)  ; // fine: c is of a complete type now 

http://coliru.stacked-crooked.com/a/92046f7ed520308f

This would be fine:
Header:
1
2
const int L = 3 ;
extern double  grows[][L+1];


Implementation:
1
2
// #include ...
double grows[2][L+1] = { { 0, 1, 2, 3}, { 4, 5, 6, 7} };
The problem with having a header like
1
2
3
4
5
6
7
#ifndef GUARD_Global_Defs
#define GUARD_Global_Defs

const int L = 3 ;
extern double  grows[][L+1]

#endif 

and including it in multiple files is that the compiler complains that the variable L is multiply defined.
So I made it a pure declaration (extern int L;). But then I cannot use L in declaring the array size...
You do not need the constant.

http://en.cppreference.com/w/cpp/types/extent
Huh? you mean like declaring it as extern double grows[][] in the header file? The compiler complains saying that all dimensions except the first must be known at compile time.
extern double grows[][3+1];

http://en.cppreference.com/w/cpp/types/extent
Yes extern double grows[][3+1]; works, but when I want to change the L constant, now I have to make changes in two files. Moreover, I have 6 arrays which depend on L, so I have to make changes in 7 places.

Ideally I would just have to make one change, eg
const int L=3;
to
const int L= 9;
and everything else would magically work out.

I guess this cannot be done without using #define
By default, constants have internal linkage. This header is fine (assuming that the include guard is unique).
globals.h
1
2
3
4
5
6
7
#ifndef GUARD_Global_Defs
#define GUARD_Global_Defs

const int L = 3 ;
extern double  grows[][L+1];

#endif  

http://coliru.stacked-crooked.com/a/67e7b54192f3fdf6

It can be included in multiple source files:
globals.cpp
1
2
3
#include "globals.h"

double  grows[2][L+1] = { { 0, 1, 2, 3}, { 4, 5, 6, 7} };

http://coliru.stacked-crooked.com/a/40d1849fd7cbceae

main.cpp
1
2
3
4
5
6
7
8
#include "globals.h"
#include <iostream>

int main()
{
    for( double d : grows[1] ) std::cout << d << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/f439e4f06d094240


In contrast, this would give a 'multiply defined' error (external linkage for the constant):
1
2
3
4
5
6
7
#ifndef GUARD_Global_Defs
#define GUARD_Global_Defs

extern const int L = 3 ; // *** extern
extern double  grows[][L+1]

#endif 
Thanks JLBorges!

That solved it.

I also read the portion in C++ primer - it clarified that with consts, it is as if a seperate variable is being defined in different files (with the same name).
Topic archived. No new replies allowed.