Fixing "Undefined Reference" Error in .o File

  • Thread starter Thread starter NeoDevin
  • Start date Start date
  • Tags Tags
    Reference
AI Thread Summary
The discussion revolves around resolving an "undefined reference" error when calling functions from a .o file, which was identified as stemming from incorrect capitalization of function names. Additionally, participants explored how to access elements in dynamically allocated two-dimensional arrays in C and C++. It was clarified that C does not support true multi-dimensional arrays with dynamic sizing beyond the first dimension, necessitating the use of pointers to arrays or typecasting for access. The conversation highlighted the distinction between multi-dimensional and ragged arrays, emphasizing that proper memory allocation and pointer management are crucial for accessing elements correctly. The thread concludes with examples demonstrating the correct allocation and access methods for both types of arrays.
NeoDevin
Messages
334
Reaction score
2
I'm trying to call a function from a .o file, and it keeps telling me:

"undefined reference to ..." where the ... is whatever function I'm trying to call.

Do any of you have any idea what's wrong with this?
 
Technology news on Phys.org
How did you compile your code - what command did you use?
A .o file has to be linked into your code (C example)
Code:
cc myfile.c anotherfile.o -o myfile
 
I figured it out, I had wrong capitalization of the function name.

Next question:

If I have a pointer to the first element of a dynamically allocated 2 dimension array, is there any way to use two subscripts with that pointer.
Code:
//I create a dynamically allocated array:
int i;
int N = 100;
double **A;
double *p;
A = new double *[N]
for(i = 0; i < N; i++) A[i] = new double [N];

// and point a pointer to the first element.
p = A[0];

//now I want to be able to use it like this:

p[3][4] = 12;
 
C really has no concept of multi-dimensional arrays; all arrays are really stored in a one-dimensional format in memory. When you want to access element [3][4], the compiler actually performs some math to get a one-dimensional index: 3 * (number of elemts in row) + 4. If the compiler doesn't know how many elements are in a row, it cannot do this.

So, if all you're given is a pointer to the first element of a multidimensional array, you are effectively screwed.

- Warren
 
There's no way to typecast it, if you know the number of elements in the row?
 
Your code creates an array of pointers, this is not a matrix.

In the matrix examples below, note that "double (*pmd)[5]" declares pmd to be a pointer to an array of 5 doubles,
as opposed to "double *pmd[5]" which is an array of 5 pointers to double; the parenthesis around *pmd is what makes the difference.

C++ matrix example:

Code:
    double (*pmd)[5] = new double[4][5];
    pmd[1][2] = 1.0;
    delete [] pmd;

C++ array with matrix typecast example:
Code:
    double *pad = new double[20];
    ((double (*)[5])pad)[1][2] = (double) 1.0;
    delete []pad;

C matrix:
Code:
    double (*pmd)[5] = (void *)malloc(4*5*sizeof(double));
    pmd[1][2] = 1.0;
    free(pmd);

C array with matrix typecast:

Code:
    double *pad = (void *)malloc(4*5*sizeof(double));
    ((double (*)[5])pad)[1][2] = 1.0;
    free((void *)pad);

Using Microsoft compiler, all 3 examples produce essentially the same code:
allocate 160 bytes,
set [ptr+56] = [ptr + (((1 x 5) + 2) x sizeof(double))] to 1.0
free ptr.
 
Last edited:
Jeff Reid said:
Code:
    double (*pmd)[5] = new double[4][5];
    pmd[1][2] = 1.0;
    delete [] pmd;

Can you do this if you need both dymensions to be dynamically allocated?

Jeff Reid said:
C++ array with matrix typecast example:
Code:
    double *pad = new double[20];
    ((double (*)[5])pad)[1][2] = (double) 1.0;
    delete []pad;

This is what I was looking for. Thank you.
 
NeoDevin said:
Can you do this if you need both dimensions to be dynamically allocated?
Not with the Microsoft compilers. Only the first dimension of a muti-dimensional array is allowed to be dynamic, the rest have to be compile time constants. You would need to use a vector of pointers to accomplish the equivalent, and would have to iterate for each allocation and/or freeing of a vector. The entity would be a mix of pointers and doubles.

In the examples above, what I really created was a pointer to an vector of 5 doubles, such as "double (*pv)[5]". C and C++ allow pv[j] or (*pv+i)[j], effectively promoting the pointer to a vector to a pointer to a matrix.

For a more familiar example, "double *ps" is a pointer to a scalar double (just one instance), and C and C++ allow ps or *(ps+i), effectively promoting the pointer to a scalar to a pointer to a vector.

Here is an example that actually uses a pointer to a matrix:
Code:
    static double *ps = new double[40];         // poitner to scalar
    double (*pv)[5] = (double (*)[5])ps;        // pointer to vector
    double (*pm)[4][5] = (double (*)[4][5])ps;  // pointer to matrix
    ps[6] = 1.0;                                // *(ps +  6) = 1.0
    pv[1][2] = 1.0;                             // *(ps +  7) = 1.0
    (*pm)[3][4] = 1.0;                          // *(ps + 19) = 1.0
    pm[1][2][3] = 1.0;                          // *(ps + 33) = 1.0
    delete [] ps;
 
Last edited:
Jeff Reid said:
Not with the Microsoft compilers. Only the first dimension of a muti-dimensional array is allowed to be dynamic, the rest have to be compile time constants.

In the examples above, what I really created was a pointer to an vector of 5 doubles, such as "double (*pv)[5]". C and C++ allow pv[j] or *(pv+i)[j], effectively promoting the pointer to a vector to a pointer to a matrix.

As an analogy, "double *ps" is a pointer to a scalar double (just one instance), and C and C++ allow ps or *(ps+i), effectively promoting the pointer to a scalar to a pointer to a vector.

Here is an example that actually uses a pointer to a matrix:
Code:
    static double *ps = new double[40];         // poitner to scalar
    double (*pv)[5] = (double (*)[5])ps;        // pointer to vector
    double (*pm)[4][5] = (double (*)[4][5])ps;  // pointer to matrix
    ps[6] = 1.0;                                // *(ps +  6) = 1.0
    pv[1][2] = 1.0;                             // *(ps +  7) = 1.0
    (*pm)[3][4] = 1.0;                          // *(ps + 19) = 1.0
    pm[1][2][3] = 1.0;                          // *(ps + 33) = 1.0
    delete [] ps;


My code from post 3 works to create a two dimensional dynamically allocated array. Try it. I don't understand why you tell me that it doesn't work.

Code:
//next two lines create a dynamically allocated N by M array A[N][M]
double **A = new double *[N];
for(i = 0; i < N; i++) A[i] = new double[M];

//we can then use it like this
A[1][3] = 14;
cout << A[1][3];

What I was asking was not how to create the array (though if there is a better way, I'd be glad to hear it, this method always seemed inelegant to me), but if I later have a pointer pointing to the first element of the array, how to use it with two subscripts.

Code:
//make a pointer and point it to the first element of A
double *p;
p = A[0];

//I wanted to be able to use p something like p[1][3]
//you gave me the answer by typecasting the pointer

((double (*)[M])p)[1][3] = 14;
cout << ((double (*)[M])p)[1][3];
 
  • #10
You are talking past one another, thanks to how C (and C++) treats multi-dimensional and ragged arrays. Jeff Reid is creating multi-dimensional arrays while NeoDevin is creating ragged arrays. A multi-dimensional array occupies a monolithic block of memory and is allocated by a single new/malloc, while a ragged array comprises multiple chunks of memory and requires multiple new/malloc invocations. Both are accessed the same way: [noparse]multi_dim_array[index1][index2][/noparse] versus [noparse]ragged_array[index1][index2][/noparse].
 
  • #11
NeoDevin said:
If I have a pointer pointing to the first element of the array, how to use it with two subscripts.
You can't. You need a pointer to one of the pointers in A in order to use two subscripts. If you just copy the first pointer in A to a pointer to double, "p = A[0]", there's no way to get to A[1], A[2], ..., from p, because the vector of pointers only exists in A, while p only contains a single pointer. You'd have to create a duplicate of A, a pointer to a pointer to a double. You can implement this with just two allocated chunks of memory, by allocating a large vector, then setting A[] to sequentially higher locations in the large vector:
Code:
int main()
{
    int i0, i1;                         // indexes
    int d0, d1;                         // dimension sizes

    d0 = 4;
    d1 = 5;

    double **apd = new double *[d0];    // allocate vector of pointers
    double *pd = new double[d0*d1];     // allocate large vector of doubles

    double *pt = pd;                    // temp pointer to vector of doubles
    for(i0 = 0; i0 < d0; i0++){         // set pointers to vectors of doubles
        apd[i0] = pt;
        pt += d1;}

    double **ppd = apd;                 // copy of apd;

    for(i0 = 0; i0 < d0; i0++)          // access the data
        for(i1 = 0; i1 < d1; i1++)
            ppd[i0][i1] = 1.0*i0*i1;

    delete [] pd;                       // delete large vector of doubles
    delete [] apd;                      // delete vector of pointers
    return(0);
}


D H said:
You are talking past one another, thanks to how C (and C++) treats multi-dimensional and ragged arrays. Jeff Reid is creating multi-dimensional arrays while NeoDevin is creating ragged arrays.
I already mentioned this in post #6: "Your code creates an array of pointers, this is not a matrix."
 
Last edited:

Similar threads

Back
Top