0

I am writing a C programme in which there will be several arrays which lengths are configured in a data file.

I am trying to read I and J from OFDMA.dat, and create arrays Noise, Bw .etc

The lines I have commented belong to the original programme which works:

//#define I 3;
//#define J 2;
//#define NUMROWS    (1+I+2*I*J)
//#define NUMCOLS    3*I*J
//#define NUMNZ      6*I*J

Then I tried to read from OFDMA.dat with following code:

while (fgets(buffer, 80, dat) != NULL) {
if (buffer[0] == '#') continue;

if (counter == 1){
    maxIter = atoi(buffer);
    printf("maxIter \n");
}

if (counter == 2){
    Pwr = atof(buffer);
    printf("Pwr \n");
}

if (counter == 3){
    I = atoi(buffer);
    printf("I \n");
    Bw = (double*)malloc(sizeof(double)*I);
    Noise = (double*)malloc(sizeof(double)*I);

}

if (counter == 4){
    J = atoi(buffer);
    printf("J \n");
}
if (counter>4 && counter <= 4 + I){
    Noise[counter - 5] = atof(buffer);
    printf("Noise[%d]: %lf\n", counter - 5, Noise[counter - 5]);
}
if (counter>4 + I&&counter<4 + 2 * I){
    Bw[counter - 5 - I] = atof(buffer);
    printf("Bw[%d]: %lf\n", counter - I - 5, Bw[counter - I - 5]);
}

counter++;
}

Then visual studio says:

1>OFDMA.c(96): error C2057: expected constant expression
1>OFDMA.c(96): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(102): error C2057: expected constant expression
1>OFDMA.c(102): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(135): error C2057: expected constant expression
1>OFDMA.c(135): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(135): error C2133: 'x' : unknown size
1>OFDMA.c(136): error C2057: expected constant expression
1>OFDMA.c(136): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(136): error C2133: 'slack' : unknown size
1>OFDMA.c(352): error C2057: expected constant expression
1>OFDMA.c(352): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(546): error C2057: expected constant expression
1>OFDMA.c(546): error C2466: cannot allocate an array of constant size 0

In those lines, I and J are used in declaring arrays. For example:

static int
setproblemdata(char **probname_p, int *numcols_p, int *numrows_p, int *objsen_p,
double **obj_p, double **rhs_p, char **sense_p, int **matbeg_p,
int **matcnt_p, int **matind_p, double **matval_p, double **lb_p,
double **ub_p, char **ctype_p, double Noise_p[I]);

The full codes:

/* Bring in the CPLEX function declarations and the C library
header file stdio.h with the include of cplex.h. */

#include <ilcplex/cplex.h>

/* Bring in the declarations for the string functions */

#include <string.h>
#include <stdlib.h>
#include <math.h>

#include <string.h>

/* The problem we are optimizing will have I channels, J users.
* So there will be 1+I+2*I*J rows, 3*I*J columns, and 5*I*J nonzeros.  */

//#define I 3;
//#define J 2;
//#define NUMROWS    (1+I+2*I*J)
//#define NUMCOLS    3*I*J
//#define NUMNZ      6*I*J

int I, J;
int maxIter;
double Pwr;
double* Bw;
double* Noise;

/* Include declaration for function at end of program */
static int readdata(){


    int counter = 1;

    FILE * dat;
    dat = fopen("OFDMA.dat", "r");


    char buffer[80];
    if (!dat) // equivalent to saying if ( in_file == NULL ) 
    {
        printf("oops, file can't be read\n");
        return 1;
    }


    while (fgets(buffer, 80, dat) != NULL) {
        if (buffer[0] == '#') continue;

        if (counter == 1){
            maxIter = atoi(buffer);
            printf("maxIter \n");
        }

        if (counter == 2){
            Pwr = atof(buffer);
            printf("Pwr \n");
        }

        if (counter == 3){
            I = atoi(buffer);
            printf("I \n");
            Bw = (double*)malloc(sizeof(double)*I);
            Noise = (double*)malloc(sizeof(double)*I);
                    NUMROWS=1+I+2*I*J;
                    NUMCOLS=4*I*J;
                    NUMNZ=6*I*J;
        }

        if (counter == 4){
            J = atoi(buffer);
            printf("J \n");
        }
        if (counter>4 && counter <= 4 + I){
            Noise[counter - 5] = atof(buffer);
            printf("Noise[%d]: %lf\n", counter - 5, Noise[counter - 5]);
        }
        if (counter>4 + I&&counter<4 + 2 * I){
            Bw[counter - 5 - I] = atof(buffer);
            printf("Bw[%d]: %lf\n", counter - I - 5, Bw[counter - I - 5]);
        }

        counter++;
    }


    fclose(dat);



    return 0;
}
static int
setproblemdata(char **probname_p, int *numcols_p, int *numrows_p, int *objsen_p,
double **obj_p, double **rhs_p, char **sense_p, int **matbeg_p,
int **matcnt_p, int **matind_p, double **matval_p, double **lb_p,
double **ub_p, char **ctype_p, double Noise_p[I]);

static void
free_and_null(char **ptr);

static int
addcuts(double **matval_p, double **rhs_p, double pbar_p[I*J], const double Bw_[I], double Noise_p[I]);

int main(void) {


    /* Declare pointers for the variables and arrays that will contain
    the data which define the LP problem.  The setproblemdata() routine
    allocates space for the problem data.  */

    char *probname = NULL;
    int numcols;
    int numrows;
    int objsen;
    double *obj = NULL;
    double *rhs = NULL;
    char *sense = NULL;
    int *matbeg = NULL;
    int *matcnt = NULL;
    int *matind = NULL;
    double *matval = NULL;
    double *lb = NULL;
    double *ub = NULL;
    char *ctype = NULL;
    double *pbar = NULL;



    /* Declare and allocate space for the variables and arrays where we will
    store the optimization results including the status, objective value,
    variable values, and row slacks. */

    int solstat;
    double objval;
    double x[NUMCOLS];
    double slack[NUMROWS];

    CPXENVptr env = NULL;
    CPXLPptr lp = NULL;
    int status;
    int i, j;
    int counter;
    int cur_numrows, cur_numcols;

    /* Import Data from file OFDMA.dat*/

    status = readdata();
    if (status){
        fprintf(stderr, "Failure to read data from file. \n");
        goto TERMINATE;
    }



    /* Initialize the CPLEX environment */

    env = CPXopenCPLEX(&status);

    /* If an error occurs, the status value indicates the reason for
    failure.  A call to CPXgeterrorstring will produce the text of
    the error message.  Note that CPXopenCPLEX produces no output,
    so the only way to see the cause of the error is to use
    CPXgeterrorstring.  For other CPLEX routines, the errors will
    be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON.  */

    if (env == NULL) {
        char errmsg[CPXMESSAGEBUFSIZE];
        fprintf(stderr, "Could not open CPLEX environment.\n");
        CPXgeterrorstring(env, status, errmsg);
        fprintf(stderr, "%s", errmsg);
        goto TERMINATE;
    }

    /* Turn on output to the screen */

    status = CPXsetintparam(env, CPXPARAM_ScreenOutput, CPX_ON);
    if (status) {
        fprintf(stderr, "Failure to turn on screen indicator, error %d.\n",
            status);
        goto TERMINATE;
    }

    /* Fill in the data for the problem.  */

    status = setproblemdata(&probname, &numcols, &numrows, &objsen, &obj, &rhs,
        &sense, &matbeg, &matcnt, &matind, &matval, &lb, &ub, &ctype, Noise);
    if (status) {
        fprintf(stderr, "Failed to build problem data arrays.\n");
        goto TERMINATE;
    }

    /* Create the problem. */

    lp = CPXcreateprob(env, &status, probname);

    /* A returned pointer of NULL may mean that not enough memory
    was available or there was some other problem.  In the case of
    failure, an error message will have been written to the error
    channel from inside CPLEX.  In this example, the setting of
    the parameter CPXPARAM_ScreenOutput causes the error message to
    appear on stdout.  */

    if (lp == NULL) {
        fprintf(stderr, "Failed to create LP.\n");
        goto TERMINATE;
    }

    /* Main Loop */

    for (i = 0; i < maxIter; i++) {
        /* Now copy the problem data into the lp */

        status = CPXcopylp(env, lp, numcols, numrows, objsen, obj, rhs, sense,
            matbeg, matcnt, matind, matval, lb, ub, NULL);

        if (status) {
            fprintf(stderr, "Failed to copy problem data.\n");
            goto TERMINATE;
        }

        /* Now copy the ctype array */

        status = CPXcopyctype(env, lp, ctype);
        if (status) {
            fprintf(stderr, "Failed to copy ctype\n");
            goto TERMINATE;
        }

        /* Optimize the problem and obtain solution. */

        status = CPXmipopt(env, lp);
        if (status) {
            fprintf(stderr, "Failed to optimize MIP.\n");
            goto TERMINATE;
        }

        solstat = CPXgetstat(env, lp);

        /* Write the output to the screen. */

        printf("\nSolution status = %d\n", solstat);

        status = CPXgetobjval(env, lp, &objval);
        if (status) {
            fprintf(stderr, "No MIP objective value available.  Exiting...\n");
            goto TERMINATE;
        }

        cur_numcols = CPXgetnumcols(env, lp);

        status = CPXgetx(env, lp, x, 0, cur_numcols - 1);
        if (status) {
            fprintf(stderr, "Failed to get optimal integer x.\n");
            goto TERMINATE;
        }

        printf("Solution value  = %f\n\n", objval);

        /* Add Cuts to the problem */

        addcuts(&matval, &rhs, x, Bw, Noise);


    }
    /* The size of the problem should be obtained by asking CPLEX what
    the actual size is, rather than using what was passed to CPXcopylp.
    cur_numrows and cur_numcols store the current number of rows and
    columns, respectively.  */

    cur_numrows = CPXgetnumrows(env, lp);
    cur_numcols = CPXgetnumcols(env, lp);

    status = CPXgetx(env, lp, x, 0, cur_numcols - 1);
    if (status) {
        fprintf(stderr, "Failed to get optimal integer x.\n");
        goto TERMINATE;
    }


    status = CPXgetslack(env, lp, slack, 0, cur_numrows - 1);
    if (status) {
        fprintf(stderr, "Failed to get optimal slack values.\n");
        goto TERMINATE;
    }

    for (i = 0; i < cur_numrows; i++) {
        printf("Row %d:  Slack = %10f\n", i, slack[i]);
    }

    for (j = 0; j < cur_numcols; j++) {
        printf("Column %d:  Value = %10f\n", j, x[j]);
    }

    /* Finally, write a copy of the problem to a file. */

    status = CPXwriteprob(env, lp, "OFMDA.lp", NULL);
    if (status) {
        fprintf(stderr, "Failed to write LP to disk.\n");
        goto TERMINATE;
    }

TERMINATE:

    /* Free up the problem as allocated by CPXcreateprob, if necessary */

    if (lp != NULL) {
        status = CPXfreeprob(env, &lp);
        if (status) {
            fprintf(stderr, "CPXfreeprob failed, error code %d.\n", status);
        }
    }

    /* Free up the CPLEX environment, if necessary */

    if (env != NULL) {
        status = CPXcloseCPLEX(&env);

        /* Note that CPXcloseCPLEX produces no output,
        so the only way to see the cause of the error is to use
        CPXgeterrorstring.  For other CPLEX routines, the errors will
        be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */

        if (status) {
            char errmsg[CPXMESSAGEBUFSIZE];
            fprintf(stderr, "Could not close CPLEX environment.\n");
            CPXgeterrorstring(env, status, errmsg);
            fprintf(stderr, "%s", errmsg);
        }
    }

    /* Free up the problem data arrays, if necessary. */

    free_and_null((char **)&probname);
    free_and_null((char **)&obj);
    free_and_null((char **)&rhs);
    free_and_null((char **)&sense);
    free_and_null((char **)&matbeg);
    free_and_null((char **)&matcnt);
    free_and_null((char **)&matind);
    free_and_null((char **)&matval);
    free_and_null((char **)&lb);
    free_and_null((char **)&ub);
    free_and_null((char **)&ctype);

    return (status);

} /* END main */

static int setproblemdata(char **probname_p, int *numcols_p, int *numrows_p,
    int *objsen_p, double **obj_p, double **rhs_p, char **sense_p,
    int **matbeg_p, int **matcnt_p, int **matind_p, double **matval_p,
    double **lb_p, double **ub_p, char **ctype_p, double Noise_p[I]) {
    char *zprobname = NULL; /* Problem name <= 16 characters */
    double *zobj = NULL;
    double *zrhs = NULL;
    char *zsense = NULL;
    int *zmatbeg = NULL;
    int *zmatcnt = NULL;
    int *zmatind = NULL;
    double *zmatval = NULL;
    double *zlb = NULL;
    double *zub = NULL;
    char *zctype = NULL;
    int status = 0;
    int i, j; //channel and user
    int counter = 0; //counter

    zprobname = (char *)malloc(16 * sizeof (char));
    zobj = (double *)malloc(NUMCOLS * sizeof (double));
    zrhs = (double *)malloc(NUMROWS * sizeof (double));
    zsense = (char *)malloc(NUMROWS * sizeof (char));
    zmatbeg = (int *)malloc(NUMCOLS * sizeof (int));
    zmatcnt = (int *)malloc(NUMCOLS * sizeof (int));
    zmatind = (int *)malloc(NUMNZ * sizeof (int));
    zmatval = (double *)malloc(NUMNZ * sizeof (double));
    zlb = (double *)malloc(NUMCOLS * sizeof (double));
    zub = (double *)malloc(NUMCOLS * sizeof (double));
    zctype = (char *)malloc(NUMCOLS * sizeof (char));

    if (zprobname == NULL || zobj == NULL || zrhs == NULL || zsense == NULL
        || zmatbeg == NULL || zmatcnt == NULL || zmatind == NULL
        || zmatval == NULL || zlb == NULL || zub == NULL || zctype == NULL) {
        status = 1;
        goto TERMINATE;
    }

    strcpy(zprobname, "example");

    /* The code is formatted to make a visual correspondence
    between the mathematical linear program and the specific data
    items.   */

    /* Objective Function*/

    /* coefficients of p_ij and x_ij*/
    for (i = 0; i < 2 * I * J; i++) {
        zobj[i] = 0;
    }
    /* coefficients of e_ij*/
    for (i = 2 * I * J; i < 3 * I * J; i++) {
        zobj[i] = 1;
    }

    /* Constraints */

    /*
    * Non-zeros
    *
    * Every p_ij appears twice, at the 0th and (I+i)th constraints.
    * Every x_ij appears twice, at the ...........
    * Every e_ij appears once, at the (1+I+I*J+i)th constraint.
    */

    for (i = 0; i < I * J; i++) {
        zmatbeg[i] = 3 * i;
        zmatcnt[i] = 3;
    }
    for (i = 0; i < I * J; i++) {
        zmatbeg[I * J + i] = 3 * I * J + 2 * i;
        zmatcnt[I * J + i] = 2;
    }
    for (i = 0; i < I * J; i++) {
        zmatbeg[2 * I * J + i] = 5 * I * J + i;
        zmatcnt[2 * I * J + i] = 1;
    }

    /*
    * p_ij appears at the 0th and (I+i+1)th constraints, coefficient is 1.
    */

    for (i = 0; i < I * J; i++) {
        zmatind[3 * i] = 0;
        zmatval[3 * i] = 1.0;
        zmatind[3 * i + 1] = I + i + 1;
        zmatval[3 * i + 1] = 1.0;
        zmatind[3 * i + 2] = 1 + I + I * J + i;
        zmatval[3 * i + 2] = -1.0;
    }

    /*
    * x_ij
    */

    int ztmpind = I + 1;
    for (i = 0; i < 2 * I * J; i += 2) {
        zmatind[3 * I * J + i] = i / (2 * J) + 1;
        zmatval[3 * I * J + i] = 1;
        zmatind[3 * I * J + i + 1] = ztmpind;
        zmatval[3 * I * J + i + 1] = -1 * Pwr;
        ztmpind++;
    }

    /*
    * e_ij appears at the (1+I+I*J+i)th constraint.
    */

    for (i = 0; i < I * J; i++) {
        zmatind[5 * I * J + i] = 1 + I + I * J + i;
        zmatval[5 * I * J + i] = 1;
    }

    /*
    * Domain of variables
    */

    for (i = 0; i < I * J; i++) {
        zlb[i] = 0.0;
        zub[i] = CPX_INFBOUND;
        zctype[i] = 'C';
    }
    for (i = I * J; i < 2 * I * J; i++) {
        zlb[i] = 0.0;
        zub[i] = 1.0;
        zctype[i] = 'I';
    }

    for (i = 2 * I * J; i < 3 * I * J; i++) {
        zlb[i] = 0.0;
        zub[i] = CPX_INFBOUND;
        zctype[i] = 'C';
    }

    /* The right-hand-side values don't fit nicely on a line above.  So put
    them here.  */

    zsense[0] = 'L';
    zrhs[0] = Pwr;

    for (i = 0; i < I; i++) {
        zsense[i + 1] = 'L';
        zrhs[i + 1] = 1;

    }
    for (i = 0; i < I * J; i++) {
        zsense[I + i + 1] = 'L';
        zrhs[I + 1 + i] = 0;
    }

    counter = 0;
    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            zsense[1 + I + I * J + counter] = 'L';
            zrhs[1 + I + I * J + counter] = log(1 + Pwr / Noise_p[i]);
            counter++;
        }
    }

TERMINATE:

    if (status) {
        free_and_null((char **)&zprobname);
        free_and_null((char **)&zobj);
        free_and_null((char **)&zrhs);
        free_and_null((char **)&zsense);
        free_and_null((char **)&zmatbeg);
        free_and_null((char **)&zmatcnt);
        free_and_null((char **)&zmatind);
        free_and_null((char **)&zmatval);
        free_and_null((char **)&zlb);
        free_and_null((char **)&zub);
        free_and_null((char **)&zctype);
    }
    else {
        *numcols_p = NUMCOLS;
        *numrows_p = NUMROWS;
        *objsen_p = CPX_MAX; /* The problem is maximization */

        *probname_p = zprobname;
        *obj_p = zobj;
        *rhs_p = zrhs;
        *sense_p = zsense;
        *matbeg_p = zmatbeg;
        *matcnt_p = zmatcnt;
        *matind_p = zmatind;
        *matval_p = zmatval;
        *lb_p = zlb;
        *ub_p = zub;
        *ctype_p = zctype;
    }
    return (status);

} /* END setproblemdata */

/* Add Cuts to the problem */

static int addcuts(double **matval_p, double **rhs_p, double pbar_p[I*J], const double Bw_p[I], double Noise_p[I]) {
    double *zmatval = NULL;
    double *zrhs = NULL;
    int status = 0;
    int i, j;
    int counter;


    zrhs = (double *)malloc(NUMROWS * sizeof (double));
    zmatval = (double *)malloc(NUMNZ * sizeof (double));

    if (zrhs == NULL || zmatval == NULL) {
        status = 1;
        goto TERMINATE;
    }
    zrhs = *rhs_p;
    zmatval = *matval_p;
    for (i = 0; i < I * J; i++) {
        printf("pbar_%d is %f\n", i, pbar_p[i]);
    }
    /*

    */
    counter = 0;
    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            printf("e_bar: %f\n", Bw_p[i] * log2(1 + pbar_p[counter] / Noise_p[i]));
        }
    }
    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            printf("xx: %f\n", -Bw_p[i] / (log(2)*(Noise_p[i] + pbar_p[i])));
        }
    }
    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            zmatval[3 * i + 2] = -Bw_p[i] / (log(2)*(Noise_p[i] + pbar_p[i]));
        }
    }
    for (i = 0; i < I; i++) {
        for (j = 0; j < J; j++) {
            zrhs[1 + I + I * J + i] = Bw_p[i] * log2(1 + pbar_p[i] / Noise_p[i]) - Bw_p[i] / (log(2)*(Noise_p[i] + pbar_p[i])) * pbar_p[i];
        }
    }



TERMINATE:

    if (status) {
        free_and_null((char **)&zrhs);
    }
    else {
        *rhs_p = zrhs;
    }
    return (status);

} /* END addcuts */

/* This simple routine frees up the pointer *ptr, and sets *ptr to NULL */

static void free_and_null(char **ptr) {
    if (*ptr != NULL) {
        free(*ptr);
        *ptr = NULL;
    }
} /* END free_and_null */

Can anybody give me an example please?

Zhaoyu ZHONG
  • 133
  • 1
  • 1
  • 9

3 Answers3

1

EDIT 2 (assigning values to #define value)
There are many parts to your code that need to be addressed, however, sticking only to the part you have asked about, consider this section of your code:

   Bw = (double*)malloc(sizeof(double)*I);
    Noise = (double*)malloc(sizeof(double)*I);
            NUMROWS=1+I+2*I*J;
            NUMCOLS=4*I*J;
            NUMNZ=6*I*J;

It is not the malloc statements that are being addressed by the error messages: example:

1>OFDMA.c(96): error C2057: expected constant expression
1>OFDMA.c(96): error C2466: cannot allocate an array of constant size 0
...
...

rather the lines where you are attempting to assign values to NUMROWS, NUMCOLS etc. As I have said below, these you have created using #define, and are not changeable during run-time.

EDIT (to address I & J) When I try to read I and J from a data file, the visual studio doesn't allow me to do so saying:

expected constant expression

You've created I & J as #defines,

#define I          ii
#define J          2

they are therefore not changeable during runtime. If you want them to be changeble, created them as int, char[], or double. example:

char I[10];
int J;

They will then be able to accept assignments during run time.

It is not clear from your question exactly what you are having problems with, reading the initializer value in from a file, or using it to initialize a variable. This addresses the initialization part only:

C99 allows for variable array initializers, so reading values in from a file, (and converting them from string to int or float) then using them to initialize an array, is completely legal. For example:

float read_and_process(int n)
{
    float   vals[n];//variable array initializer "n"

    for (int i = 0; i < n; i++)
        vals[i] = read_val();
    return process(vals, n);
}  

Reference1
Reference2

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • sorry, I also realized the code is a mess. I am just trying to edit the code and the question to make it clearer. – Zhaoyu ZHONG Aug 15 '15 at 20:13
  • @ZhaoyuZHONG - There are 3 good answers. Do any of them address the central need? If not, you should narrow the scope a little so your need is known. :) – ryyker Aug 15 '15 at 20:17
  • Hi, thank you for your patience. I am new to both C and stackoverflow. Sorry for the bad way of answering. I tried to lessen my code but it seemed confused all of you. I have edited the code and question, hope it is clearer now. Thanks a lot. – Zhaoyu ZHONG Aug 15 '15 at 20:28
  • I have commented those rows defining I and J ... Those are just used to test what I can deal with them. – Zhaoyu ZHONG Aug 15 '15 at 20:41
  • Where are NUMROWS, NUMCOLS etc defined? I cannot find them in your code. – ryyker Aug 15 '15 at 20:43
  • Create as small an example as possible that still illustrates the problem you are seeing. If you follow ***[this method](http://sscce.org/)***, it will be possible for someone to load your example into a compiler then help you interpret the error messages. Currently, your code example as it exists now is not compilable. – ryyker Aug 15 '15 at 20:46
  • Thank you very much. I think I have got ya. I changed the code, it seems working. – Zhaoyu ZHONG Aug 15 '15 at 20:55
0

You first have to understand that the preprocessor will change every instance of I and J to their respective values of 3 and 2 before the actual compilation kicks in and spits out this error message.

To dynamically allocate an array you need to use malloc. You can find plenty of example by Googling.

Tarik
  • 10,810
  • 2
  • 26
  • 40
0

In C, arrays length are constant and they are defined in compiling time. If you want to trade with a variable-length array, you have to use malloc:

double* B;
double* N;
double* NZmatrix;

static int main(){
    int I, NZ;
    I = 2;
    NZ = 3;
    B = (double*)malloc(sizeof(double)*I);
    N = (double*)malloc(sizeof(double)*I)
    NZmatrix = (double*)malloc(sizeof(double)*NZ)


}

And I and NZ are integer variables that contain the desired length.

  • where did you read that `main` can be declare to be `static`? http://stackoverflow.com/questions/924890/can-the-c-main-function-be-static – Jason Hu Aug 15 '15 at 20:27
  • In C, casting the return of [m][c][re]alloc() is ***[not recommended](http://stackoverflow.com/questions/953112/should-i-explicitly-cast-mallocs-return-value)***. – ryyker Aug 15 '15 at 20:29