0

To make it straight forward: one can see there are two function declaration below.

void tableau_initialize(int Rn, int slack_num,  int Cn, int A[Rn][Cn], int B[Rn], int C[Cn+1], float ***A_tableau, float **obj_array);
    
void array_debug(int row, int col, float *A);

Putting these two functions together into one program as follows.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
void tableau_initialize(int Rn, int slack_num,  int Cn, int A[Rn][Cn], int B[Rn], int C[Cn+1], float ***A_tableau, float **obj_array);

void array_debug(int row, int col, float *A);
int max_ele(int* dynamic_array, int size);
int main()
{   
int A[5][6] = {
    {10, 11, 12, 0, 0, 0},
    {0, 0, 0, 14, 12, 13},
    {1, 0, 0, 1, 0, 0},
    {0, 1, 0, 0, 1, 0},
    {0, 0, 1, 0, 0, 1}
};
int B[5] = {0, 0, 1, 1, 1};
int C[7] = {0, 0, 0, 0, 0, 0, 1};

float **Z;

float *optimal;
tableau_initialize(5, 2, 6, A, B, C, &Z, &optimal);
array_debug(1, 6, optimal);
}

void tableau_initialize(int Rn, int slack_num,  int Cn, int 
A[Rn][Cn], int B[Rn], int C[Cn+1], float ***A_tableau, float 
**obj_array)
{
//artificial and objective variable numbers:
int art_num = Rn - slack_num;
int obj_num = 1; 

//Non-standard variable number:
int non_std_var_num = Rn + obj_num;
//Total variable number:
int var_num = Cn+non_std_var_num;

//These arrays are respectively tableau array and results     array.
//Tableau array structure is: [standard variables, slack variables, artificial variables, objective variables.]

//Allocate arrays for A_tableau and obj_array.
*A_tableau = malloc(sizeof(float *) * non_std_var_num);
for(int i = 0; i < non_std_var_num; i++)
{
    (*A_tableau)[i] = malloc(sizeof(float) * var_num);
}

obj_array = malloc(sizeof(float) * non_std_var_num);
//This result contains results from constraints and objective function.
float B_full[non_std_var_num];

//Big M computations: with big M methods, our aim is to  minimize 
//Z = X - M*artifical variables; 
//equivalently, we want to maximize -X + M*artificial 
//variables.
float M       = 1000000.0 * max_ele(&A[0][0], Rn*Cn);

//Fill the Tableau array:
for(int i = 0; i < Rn; i++)
{
    //Array copy:
    for(int j = 0; j < Cn; j++)
    {
        (*A_tableau)[i][j] = (float)A[i][j];
    }
    //Non-standard variable addition:
    for(int j = 0; j < non_std_var_num; j++)
    {
        int result;
        //Reverse the objective variable add it 
        if((j == Rn) && (i < slack_num))
        {
            result = -C[Cn];
        }
        else
        {
            //This is adding slack and artificial variable                 coefficient;
            result = (i == j) ? 1 : 0;
        }
        (*A_tableau)[i][Cn+j] = (float)result;
    }
}

//This is the last row within Tableau, this row is very 
//special as it is the row of objective function.
for(int i = 0; i < var_num; i++)
{
    //This is the standard and slack variable coefficient: 
    if(i < Cn+slack_num)
    {
        (*A_tableau)[Rn][i] = 0;
    }
    
    else 
    {
        //This is the coefficient of obj variable.
        if(i == var_num - 1)
        {
            (*A_tableau)[Rn][i] = -(float)C[Cn];
        }
        else
        {
            (*A_tableau)[Rn][i] = -M;
        }
    }
}

//Create 1-D dynamic array:
*obj_array = malloc(sizeof(float) * 6);
//Result array copy:
for(int i = 0; i < Rn; i++)
{
    (*obj_array)[i] = (float)B[i];
}
(*obj_array)[Rn] = 0;
array_debug(1, 6, *obj_array);

}
void array_debug(int row, int col, float *A) {     
    for(int i = 0; i < row; i++)     
    {         
        for(int j = 0; j < col; j++)         
        {             
            printf("%f\t", *(A+i*col+j));         
        }         
        printf("\n");     
    }      
    printf("\n"); 
}
int max_ele(int* dynamic_array, int size)
{
    if(!dynamic_array)
    {
        return 0;
    }

    int max_ele = dynamic_array[0];
    for(int i = 1; i < size; i++)
    {
        if(max_ele < dynamic_array[i])
        {
            max_ele = dynamic_array[i];
        }
    }
    return max_ele;
}

The output from the terminal screen is as follows:

0.000000        0.000000        1.000000        1.000000        1.000000        0.000000

0.000000        0.000000        0.000000        0.000000        0.000000        0.000000

Why is array_debug printed in main() function showing that the dynamic array *optimal is filled with zeros, but in tableau_initialize(), it indicates that *optimal is a 1-D array with non-zero values? My expectation is I have two outputs like this:

0.000000        0.000000        1.000000        1.000000        1.000000        0.000000

0.000000        0.000000        1.000000        1.000000        1.000000        0.000000
19
  • Can you provide the implementation of tableau_initialize? How to create a Minimal, Reproducible Example Commented Apr 8, 2024 at 19:20
  • Can you show your output; and your expected output? Because B has non-zero values, so I'd expect non-zero values. Commented Apr 8, 2024 at 19:23
  • In line with the first comment: could you combine all the separate pieces into one comprehensive C program? That's clearer for everyone, and makes it a lot easier to copy-paste it should someone want to try themselves. Commented Apr 8, 2024 at 19:24
  • This is in tableau_initialize() function output: 0.000000 0.000000 1.000000 1.000000 1.000000 0.000000 This is in main() function 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 Commented Apr 8, 2024 at 19:25
  • The function is quite complex as a whole, let me try to make a easy reproducable example. Commented Apr 8, 2024 at 19:27

4 Answers 4

2

You have an allocation for obj_array twice in table_initialize. Once as

    obj_array = malloc(sizeof(float) * non_std_var_num);

and once as

    *obj_array = malloc(sizeof(float) * 6);

Change the first line to

    *obj_array = malloc(sizeof(float) * non_std_var_num);

and remove or comment-out the second line.

See also https://godbolt.org/z/8Kxh7e9nx .

Sign up to request clarification or add additional context in comments.

1 Comment

I wrote a more detailed explanation below, but this answer hits the core of the problem.
0

This may appear to you as pure semantics, but there's no such thing as pass by pointer in the C language. There's just pass by value (or pass by copy, for a better term). When you pass a pointer to a function, you're just passing a copy of the value of the pointer. The pointer is a separate data item that represents a memory address (in the same way a constant or variable of type int represents a restricted version of the concept mathematically known as an integer number).

Also and closely related to that, all formal parameters in a C function (that is, all the variables declared in the function prototype) are local variables. When you need to return a value (in your case, a pointer representing an address), you have two options: a) return the value (the pointer) as the result of the function (return obj_array); b) just write inside a pointer provided by the calling function.

Edit (for clarification). When you call tableau_initialize() using the &optimal syntax, you're doing two separate things: a) obtaining a new value, which is the pointer to the optimal variable (that is, a pointer to a pointer to a float); b) passing a copy of this value to the function.

Inside your tableau_initialize() function, you're overwriting the local variable obj_array (which, as I said, has a local copy of a pointer to the variable called optimal in the main program) (well, it had that, before being overwritten).

    obj_array = malloc(sizeof(float) * non_std_var_num);

This works well inside the function, and the array is created and populated. But the information (the pointer containing the address of the newly created array) never goes "up". Not just that: in the main program, even after returning from tableau_initialize(), your optimal variable is uninitialized (it contains some random address) and the content you see in array_debug() is just garbage.

As @9769953 said, you need to USE the pointer supplied by main(). May be something like:

    *obj_array = malloc(sizeof(float) * non_std_var_num);

This way, you just USE the local variable (a copy of a pointer to a pointer to a float) to write INTO the actual pointer to a float (the optimal variable defined at the main level, which is the ONLY thing for which you reserved space at the main level).

Comments

-1

Use a pointer to an array

void array_print(size_t rows, size_t cols, int (*arr)[cols])
{
    for(size_t row = 0; row < rows; row++)
    {
        for(size_t col = 0; col < cols; col++)
            printf("%d ", arr[row][col]);
        printf("\n");
    }
}

void array_init(size_t rows, size_t cols, int (*arr)[cols])
{
    for(size_t row = 0; row < rows; row++)
        for(size_t col = 0; col < cols; col++)
            arr[row][col] = rand() % 100;
}


int main(void)
{
    int A[5][6] = {
        {10, 11, 12, 0, 0, 0},
        {0, 0, 0, 14, 12, 13},
        {1, 0, 0, 1, 0, 0},
        {0, 1, 0, 0, 1, 0},
        {0, 0, 1, 0, 0, 1}
        };

    size_t rows, cols;

    srand(time(NULL));
    cols = rand() % 20;
    rows = rand() % 30;

    array_print(5, 6, A);
    printf("------------------------\n");
    
    int (*B)[cols] = malloc(rows * sizeof(*B));
    if(B)
    {
        printf("rows = %zu, cols = %zu\n", rows, cols);
        array_init(rows, cols, B);
        array_print(rows, cols, B);
        free(B);
    }
}

https://godbolt.org/z/e559nxcf6

1 Comment

ay comment silent DV-ter?
-2

Ok, I found the reason by taking some small experiments from user 9769953

I repetitively allocated the obj_array twice! One is here:

    obj_array = malloc(sizeof(float) * non_std_var_num);
    //This result contains results from constraints and objective function.

The other one is the end of tableau_initialize() function here

    *obj_array = malloc(sizeof(float) * 6);
    //Result array copy:

Somehow the Visual Studio Code GCC Compiler can't detect it and doesn't give any warnings nor errors.

Simple mistake as this, but thanks 9769953!

2 Comments

You have repeated the information in that user's answer and provided it as your own answer. Even though you think that you're thanking them by giving credit, you are in fact being rude. I recommend you delete this answer and upvote/accept the real answer.
Please, check my answer (which expands on the one provided by @9769953). The problem is not related to the compiler. You were just writing over a local copy of the pointer (instead of just using it). Also, please notice that a float * is a perfectly valid pointer to a single float value or to a sequence of several floats (ie. an array of floats). The compiler can't discern that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.