0

Minimally Verifiable Source Code - I think.I am trying to use dynamic allocation of a pointer array in a function to create a double double pointer array. When I use the code outside a struct reference it works. When I try to reference it through a pointer, it doesn't. What am I doing wrong?

This code works in GCC 4.9.2

gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.9.2-10ubuntu13' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
int main(int argc, char **argv) 
{
    double ** array;
    double row[6] = { 1.2,   2.3,   3.0,   4,   5,   6  };
    int i;
  int j;
    array = (double **) malloc( 50* sizeof(double *  )  );
    for ( i = 0; i <  50; i++)
    {
        array[i] = (double *) malloc( 6 * sizeof(double  )  );
    }
    for (j =0; j < 50; j++)
    for ( i = 0; i <  6; i++)
    {
        array[j][i] = row[i];
    }
    for (j =0; j < 50; j++)
    {   
        for (i = 0; i < 6; i++ )
        { 
            printf("%f ", ( array[0][i]) );
        }
        printf("\n ");
    }
  exit(0);  // Use exit() to exit a program, do not use 'return' from main()
}

But this code doesn't:

double ** create_array( unsigned int length,  unsigned int row)
{
    double ** array;
    int i;

    array = (double **) malloc( length * sizeof(double *  )  );
    for ( i = 0; i <  length; i++)
    {
        array[i] = (double *) malloc( row * sizeof(double  )  );
    }
    return array;
} 

I placed the double double pointer array inside a struct

typedef struct
{
        // the data area
    double ** array;
    // the number of rows in the entire entry
    unsigned int length;
    // the size of the double entity of array size
    unsigned int rowsize;
    // the current starting point 
    int start;
    // the current ending point
    int end;
    // the amount of the last write action
    // assumes the number of write in order
    unsigned int last_write[100];
    // the number of writes
    unsigned int write_count;
} DRingBuffer;

And then access through following function calls like this:

int DRingBuffer_printrow(DRingBuffer *buffer,  unsigned int row  )

When I call the function and then try to access the members it seg faults.

        printf("%f ", (buffer->array[3][2]));

This is a lot of code but someone asked for it.

 DRingBuffer *DRingBuffer_create(unsigned int length,  unsigned int row  )
    {
        int i =0;
        DRingBuffer *buffer = malloc( sizeof(DRingBuffer) );
        buffer->length  = length;
        buffer->rowsize =  row;
        buffer->start = 0;
        buffer->end = 0;
        buffer->array   = create_array(  length,  row);
        if ( buffer->array  <= 0  )
        {
            printf("ERROR: allocating arrays");
            exit( -1);
        }
        return buffer;
    }
daemondave
  • 309
  • 2
  • 12
  • 2
    How is `buffer` initialized? – ouah Oct 31 '15 at 14:29
  • 1
    How do you call the `create_buffer` function? How do you initialize the `DRingBuffer` structure? – Some programmer dude Oct 31 '15 at 14:30
  • 1
    Oh, and in C [you should not cast the result of `malloc`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) (or any other function returning `void *`). – Some programmer dude Oct 31 '15 at 14:31
  • I took out type casting, still seg fault but thanks for the tip. – daemondave Oct 31 '15 at 14:33
  • 1
    And the values for `length` and `row` are valid? What are the values? How do you call the `DRingBuffer_create` function? Can you please try to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) and show us? And I mean a MCVE of a program that *fails*. – Some programmer dude Oct 31 '15 at 14:43
  • Uploaded source code and verified it seg faults..... – daemondave Oct 31 '15 at 15:07
  • Why on earth do you have the code/comment: `exit(0); // Use exit() to exit a program, do not use 'return' from main()`? My rule is the exact antithesis of that; do not use `exit(0);` at the end of `main()`. Inside `main()`, I often use `exit()`, but not at the end. Granted, modern compilers know that `exit()` doesn't return, and using `return` avoided a warning from old compilers, but what reasoning is there for using `exit()`? – Jonathan Leffler Oct 31 '15 at 16:01
  • Why does your printing loop only access `array[0][i]`? Shouldn't it be using `array[j][i]`? – Jonathan Leffler Oct 31 '15 at 16:20

3 Answers3

0

Rather than allocating an array of pointers to other arrays, to implement a 2D array you should simply create a single allocation and then access it like array[x + y*WIDTH]. This is more efficient, less error-prone, etc.

Your code would then be simpler:

double * create_array( unsigned int length,  unsigned int row)
{
    return malloc( length * row * sizeof(double) );
} 

and the at() function might look like this:

// return element at row column
double at(double * array, unsigned int row, unsigned int col, unsigned int width)
{
            return array[ col  +  row * width ];
}
Lucas Derraugh
  • 6,929
  • 3
  • 27
  • 43
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • But then I can't use [][] referencing. So my error will move to pointer addition math...;) – daemondave Oct 31 '15 at 14:34
  • 1
    @daemondave You cannot use [][], but you can create a function at(row, col) that is as readable (or more) and does the necessary calculation. Separate allocations for each rows are needlessly inefficient. – user4815162342 Oct 31 '15 at 14:42
  • Ok so what would at() function look like. I understand I'm not completely efficient, but compared to C++ it's plenty efficient. Also, it's not my time, and I'm more of a Unix philosophy person I don't code all that often and don't get back around to code to understand what I wrote. So if it is more efficient and easy to understand great. Optimization is not my focus but I'm not against it. – daemondave Oct 31 '15 at 15:11
0

Your code in create_array() should be fine. It works OK for me. You don't show the code where you use it, so we can't be sure how you're abusing it, but it appears that you are.

Here's an adaptation of your code:

#include <stdio.h>
#include <stdlib.h>

static
double **create_array(unsigned int length,  unsigned int row)
{
    double **array;

    array = (double **) malloc(length * sizeof(double *));
    for (unsigned int i = 0; i <  length; i++)
    {
        array[i] = (double *) malloc(row * sizeof(double));
    }
    return array;
}

int main(void)
{
    double **array;
    double row[6] = { 1.2,   2.3,   3.0,   4,   5,   6  };

    array = (double **) malloc(50 * sizeof(double *));
    for (int i = 0; i <  50; i++)
    {
        array[i] = (double *) malloc(6 * sizeof(double));
    }

    for (int j = 0; j < 50; j++)
    {
        for (int i = 0; i <  6; i++)
        {
            array[j][i] = row[i] + (i + 1) * (j + 1);
        }
    }
    for (int j = 0; j < 50; j++)
    {
        for (int i = 0; i < 6; i++)
        {
            printf("%6.1f ", (array[j][i]));
        }
        putchar('\n');
    }

    for (int j = 0; j < 50; j++)
        free(array[j]);
    free(array);

    double **array2 = create_array(50, 6);

    for (int j = 0; j < 50; j++)
    {
        for (int i = 0; i <  6; i++)
        {
            array2[j][i] = row[i] + (i + 1) * (j + 1);
        }
    }
    for (int j = 0; j < 50; j++)
    {
        for (int i = 0; i < 6; i++)
        {
            printf("%6.1f ", (array2[j][i]));
        }
        putchar('\n');
    }

    for (int j = 0; j < 50; j++)
        free(array2[j]);
    free(array2);

    return(0);
}

Tested on Mac OS X 10.11.1 El Capitan, it produces:

   2.2    4.3    6.0    8.0   10.0   12.0 
   3.2    6.3    9.0   12.0   15.0   18.0 
   4.2    8.3   12.0   16.0   20.0   24.0 
   5.2   10.3   15.0   20.0   25.0   30.0 
   6.2   12.3   18.0   24.0   30.0   36.0 
   7.2   14.3   21.0   28.0   35.0   42.0 
   8.2   16.3   24.0   32.0   40.0   48.0 
   9.2   18.3   27.0   36.0   45.0   54.0 
  10.2   20.3   30.0   40.0   50.0   60.0 
  11.2   22.3   33.0   44.0   55.0   66.0 
  12.2   24.3   36.0   48.0   60.0   72.0 
  13.2   26.3   39.0   52.0   65.0   78.0 
  14.2   28.3   42.0   56.0   70.0   84.0 
  15.2   30.3   45.0   60.0   75.0   90.0 
  16.2   32.3   48.0   64.0   80.0   96.0 
  17.2   34.3   51.0   68.0   85.0  102.0 
  18.2   36.3   54.0   72.0   90.0  108.0 
  19.2   38.3   57.0   76.0   95.0  114.0 
  20.2   40.3   60.0   80.0  100.0  120.0 
  21.2   42.3   63.0   84.0  105.0  126.0 
  22.2   44.3   66.0   88.0  110.0  132.0 
  23.2   46.3   69.0   92.0  115.0  138.0 
  24.2   48.3   72.0   96.0  120.0  144.0 
  25.2   50.3   75.0  100.0  125.0  150.0 
  26.2   52.3   78.0  104.0  130.0  156.0 
  27.2   54.3   81.0  108.0  135.0  162.0 
  28.2   56.3   84.0  112.0  140.0  168.0 
  29.2   58.3   87.0  116.0  145.0  174.0 
  30.2   60.3   90.0  120.0  150.0  180.0 
  31.2   62.3   93.0  124.0  155.0  186.0 
  32.2   64.3   96.0  128.0  160.0  192.0 
  33.2   66.3   99.0  132.0  165.0  198.0 
  34.2   68.3  102.0  136.0  170.0  204.0 
  35.2   70.3  105.0  140.0  175.0  210.0 
  36.2   72.3  108.0  144.0  180.0  216.0 
  37.2   74.3  111.0  148.0  185.0  222.0 
  38.2   76.3  114.0  152.0  190.0  228.0 
  39.2   78.3  117.0  156.0  195.0  234.0 
  40.2   80.3  120.0  160.0  200.0  240.0 
  41.2   82.3  123.0  164.0  205.0  246.0 
  42.2   84.3  126.0  168.0  210.0  252.0 
  43.2   86.3  129.0  172.0  215.0  258.0 
  44.2   88.3  132.0  176.0  220.0  264.0 
  45.2   90.3  135.0  180.0  225.0  270.0 
  46.2   92.3  138.0  184.0  230.0  276.0 
  47.2   94.3  141.0  188.0  235.0  282.0 
  48.2   96.3  144.0  192.0  240.0  288.0 
  49.2   98.3  147.0  196.0  245.0  294.0 
  50.2  100.3  150.0  200.0  250.0  300.0 
  51.2  102.3  153.0  204.0  255.0  306.0 
   2.2    4.3    6.0    8.0   10.0   12.0 
   3.2    6.3    9.0   12.0   15.0   18.0 
   4.2    8.3   12.0   16.0   20.0   24.0 
   5.2   10.3   15.0   20.0   25.0   30.0 
   6.2   12.3   18.0   24.0   30.0   36.0 
   7.2   14.3   21.0   28.0   35.0   42.0 
   8.2   16.3   24.0   32.0   40.0   48.0 
   9.2   18.3   27.0   36.0   45.0   54.0 
  10.2   20.3   30.0   40.0   50.0   60.0 
  11.2   22.3   33.0   44.0   55.0   66.0 
  12.2   24.3   36.0   48.0   60.0   72.0 
  13.2   26.3   39.0   52.0   65.0   78.0 
  14.2   28.3   42.0   56.0   70.0   84.0 
  15.2   30.3   45.0   60.0   75.0   90.0 
  16.2   32.3   48.0   64.0   80.0   96.0 
  17.2   34.3   51.0   68.0   85.0  102.0 
  18.2   36.3   54.0   72.0   90.0  108.0 
  19.2   38.3   57.0   76.0   95.0  114.0 
  20.2   40.3   60.0   80.0  100.0  120.0 
  21.2   42.3   63.0   84.0  105.0  126.0 
  22.2   44.3   66.0   88.0  110.0  132.0 
  23.2   46.3   69.0   92.0  115.0  138.0 
  24.2   48.3   72.0   96.0  120.0  144.0 
  25.2   50.3   75.0  100.0  125.0  150.0 
  26.2   52.3   78.0  104.0  130.0  156.0 
  27.2   54.3   81.0  108.0  135.0  162.0 
  28.2   56.3   84.0  112.0  140.0  168.0 
  29.2   58.3   87.0  116.0  145.0  174.0 
  30.2   60.3   90.0  120.0  150.0  180.0 
  31.2   62.3   93.0  124.0  155.0  186.0 
  32.2   64.3   96.0  128.0  160.0  192.0 
  33.2   66.3   99.0  132.0  165.0  198.0 
  34.2   68.3  102.0  136.0  170.0  204.0 
  35.2   70.3  105.0  140.0  175.0  210.0 
  36.2   72.3  108.0  144.0  180.0  216.0 
  37.2   74.3  111.0  148.0  185.0  222.0 
  38.2   76.3  114.0  152.0  190.0  228.0 
  39.2   78.3  117.0  156.0  195.0  234.0 
  40.2   80.3  120.0  160.0  200.0  240.0 
  41.2   82.3  123.0  164.0  205.0  246.0 
  42.2   84.3  126.0  168.0  210.0  252.0 
  43.2   86.3  129.0  172.0  215.0  258.0 
  44.2   88.3  132.0  176.0  220.0  264.0 
  45.2   90.3  135.0  180.0  225.0  270.0 
  46.2   92.3  138.0  184.0  230.0  276.0 
  47.2   94.3  141.0  188.0  235.0  282.0 
  48.2   96.3  144.0  192.0  240.0  288.0 
  49.2   98.3  147.0  196.0  245.0  294.0 
  50.2  100.3  150.0  200.0  250.0  300.0 
  51.2  102.3  153.0  204.0  255.0  306.0 

It also doesn't leak any memory, or show any memory abuses, when run under valgrind. Or, at least, on El Capitan, the memory leaks are all from system code, completely outside the control of mortals like you and me.

There'll be those who castigate you (and probably me too) for casting the result of malloc(). Be aware of their sensibilities, and be cautious. If you compile with as stringent compilation warnings as I use, you won't run into problems:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror ddda.c -o ddda
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Interesting, what happens if you compile without these flags set, does it fail? Why won't it work on ubuntu? I take your point about typecast malloc I took those out but that wasn't the cause. Oh last question, what version of GCC? Perhaps it's resolved at the version? – daemondave Nov 01 '15 at 16:39
  • Removing the warning options makes no difference to the result. It compiles without warnings with `-std=c99`, and it runs fine. When compiled with `-std=c90`, the compiler (correctly) complains about the `for (int i = 0; …)` notations. Replace all those with `int i; int j;` at the top and remove the `int` from the loop controls and it compiles cleanly and runs under `-std=c90`. I was actually using the 'gcc' that comes with XCode 7.1 (`Apple LLVM version 7.0.0 (clang-700.1.76)`), but I also used GCC 5.2.0. One advantage of compiling cleanly is that the code works more places without problem. – Jonathan Leffler Nov 01 '15 at 17:13
  • Did you copy the code from my answer verbatim and compile it? Did it fail for you then? – Jonathan Leffler Nov 01 '15 at 17:14
  • Incidentally, I just compiled the code with gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 on an Ubuntu 14.04 LTE VM (hosted on my Mac) and ran it with a newly installed Valgrind (valgrind-3.10.0.SVN) and it both compiled cleanly and ran without error or leak. I see you're using GCC 4.9.2; I don't think it likely that the code works in 4.8.4, breaks in 4.9.2 and works in 5.2.0 — that is implausible. – Jonathan Leffler Nov 01 '15 at 17:20
0

output from run of ddda.c on ubuntu:

> gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes
> -Wstrict-prototypes -Wold-style-definition -Werror   -o working working.c  dave@hellion:/home/home/dave/src/ringbuffer/src$ ./working 
>    2.2    4.3    6.0    8.0   10.0   12.0 
>    3.2    6.3    9.0   12.0   15.0   18.0 
>    4.2    8.3   12.0   16.0   20.0   24.0 
>    5.2   10.3   15.0   20.0   25.0   30.0 
>    6.2   12.3   18.0   24.0   30.0   36.0 
>    7.2   14.3   21.0   28.0   35.0   42.0 
>    8.2   16.3   24.0   32.0   40.0   48.0 
>    9.2   18.3   27.0   36.0   45.0   54.0 
>   10.2   20.3   30.0   40.0   50.0   60.0 
>   11.2   22.3   33.0   44.0   55.0   66.0 
>   12.2   24.3   36.0   48.0   60.0   72.0 
>   13.2   26.3   39.0   52.0   65.0   78.0 
>   14.2   28.3   42.0   56.0   70.0   84.0 
>   15.2   30.3   45.0   60.0   75.0   90.0 
>   16.2   32.3   48.0   64.0   80.0   96.0 
>   17.2   34.3   51.0   68.0   85.0  102.0 
>   18.2   36.3   54.0   72.0   90.0  108.0 
>   19.2   38.3   57.0   76.0   95.0  114.0 
>   20.2   40.3   60.0   80.0  100.0  120.0 
>   21.2   42.3   63.0   84.0  105.0  126.0 
>   22.2   44.3   66.0   88.0  110.0  132.0 
>   23.2   46.3   69.0   92.0  115.0  138.0 
>   24.2   48.3   72.0   96.0  120.0  144.0 
>   25.2   50.3   75.0  100.0  125.0  150.0 
>   26.2   52.3   78.0  104.0  130.0  156.0 
>   27.2   54.3   81.0  108.0  135.0  162.0 
>   28.2   56.3   84.0  112.0  140.0  168.0 
>   29.2   58.3   87.0  116.0  145.0  174.0 
>   30.2   60.3   90.0  120.0  150.0  180.0 
>   31.2   62.3   93.0  124.0  155.0  186.0 
>   32.2   64.3   96.0  128.0  160.0  192.0 
>   33.2   66.3   99.0  132.0  165.0  198.0 
>   34.2   68.3  102.0  136.0  170.0  204.0 
>   35.2   70.3  105.0  140.0  175.0  210.0 
>   36.2   72.3  108.0  144.0  180.0  216.0 
>   37.2   74.3  111.0  148.0  185.0  222.0 
>   38.2   76.3  114.0  152.0  190.0  228.0 
>   39.2   78.3  117.0  156.0  195.0  234.0 
>   40.2   80.3  120.0  160.0  200.0  240.0 
>   41.2   82.3  123.0  164.0  205.0  246.0 
>   42.2   84.3  126.0  168.0  210.0  252.0 
>   43.2   86.3  129.0  172.0  215.0  258.0 
>   44.2   88.3  132.0  176.0  220.0  264.0 
>   45.2   90.3  135.0  180.0  225.0  270.0 
>   46.2   92.3  138.0  184.0  230.0  276.0 
>   47.2   94.3  141.0  188.0  235.0  282.0 
>   48.2   96.3  144.0  192.0  240.0  288.0 
>   49.2   98.3  147.0  196.0  245.0  294.0 
>   50.2  100.3  150.0  200.0  250.0  300.0 
>   51.2  102.3  153.0  204.0  255.0  306.0 
>    2.2    4.3    6.0    8.0   10.0   12.0 
>    3.2    6.3    9.0   12.0   15.0   18.0 
>    4.2    8.3   12.0   16.0   20.0   24.0 
>    5.2   10.3   15.0   20.0   25.0   30.0 
>    6.2   12.3   18.0   24.0   30.0   36.0 
>    7.2   14.3   21.0   28.0   35.0   42.0 
>    8.2   16.3   24.0   32.0   40.0   48.0 
>    9.2   18.3   27.0   36.0   45.0   54.0 
>   10.2   20.3   30.0   40.0   50.0   60.0 
>   11.2   22.3   33.0   44.0   55.0   66.0 
>   12.2   24.3   36.0   48.0   60.0   72.0 
>   13.2   26.3   39.0   52.0   65.0   78.0 
>   14.2   28.3   42.0   56.0   70.0   84.0 
>   15.2   30.3   45.0   60.0   75.0   90.0 
>   16.2   32.3   48.0   64.0   80.0   96.0 
>   17.2   34.3   51.0   68.0   85.0  102.0 
>   18.2   36.3   54.0   72.0   90.0  108.0 
>   19.2   38.3   57.0   76.0   95.0  114.0 
>   20.2   40.3   60.0   80.0  100.0  120.0 
>   21.2   42.3   63.0   84.0  105.0  126.0 
>   22.2   44.3   66.0   88.0  110.0  132.0 
>   23.2   46.3   69.0   92.0  115.0  138.0 
>   24.2   48.3   72.0   96.0  120.0  144.0 
>   25.2   50.3   75.0  100.0  125.0  150.0 
>   26.2   52.3   78.0  104.0  130.0  156.0 
>   27.2   54.3   81.0  108.0  135.0  162.0 
>   28.2   56.3   84.0  112.0  140.0  168.0 
>   29.2   58.3   87.0  116.0  145.0  174.0 
>   30.2   60.3   90.0  120.0  150.0  180.0 
>   31.2   62.3   93.0  124.0  155.0  186.0 
>   32.2   64.3   96.0  128.0  160.0  192.0 
>   33.2   66.3   99.0  132.0  165.0  198.0 
>   34.2   68.3  102.0  136.0  170.0  204.0 
>   35.2   70.3  105.0  140.0  175.0  210.0 
>   36.2   72.3  108.0  144.0  180.0  216.0 
>   37.2   74.3  111.0  148.0  185.0  222.0 
>   38.2   76.3  114.0  152.0  190.0  228.0 
>   39.2   78.3  117.0  156.0  195.0  234.0 
>   40.2   80.3  120.0  160.0  200.0  240.0 
>   41.2   82.3  123.0  164.0  205.0  246.0 
>   42.2   84.3  126.0  168.0  210.0  252.0 
>   43.2   86.3  129.0  172.0  215.0  258.0 
>   44.2   88.3  132.0  176.0  220.0  264.0 
>   45.2   90.3  135.0  180.0  225.0  270.0 
>   46.2   92.3  138.0  184.0  230.0  276.0 
>   47.2   94.3  141.0  188.0  235.0  282.0 
>   48.2   96.3  144.0  192.0  240.0  288.0 
>   49.2   98.3  147.0  196.0  245.0  294.0 
>   50.2  100.3  150.0  200.0  250.0  300.0 
>   51.2  102.3  153.0  204.0  255.0  306.0

It works with those CFLAGS set. So yes your tweaked code did work. I'm at a loss right now as to how, the only difference is flags set.

daemondave
  • 309
  • 2
  • 12