1

I would Like the following code to produce a structure like the one below the code. I do not get it from the code.

I want the code to create a 3D dynamic array that holds data as shown below such that when I want to print a specific string like printf("%s\n",szData[2][3]); I get "string4". Also, I would like to get a specific character from a specific location e.g putchar(szData[0][3][2] I get 'r'.

Instead the code below prints out the last saved data despite specifying a location. For example printf("%s",szData[0][0]); which should have been "string1" it prints out "string2" which is data for szData[2][1].

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

int main()
{
    char***szData;
    char temp[500];
    int i,j,k,x,n,m,index;

    printf("Rows:");
    scanf("%d",&n);

    szData=(char***)malloc(n*sizeof(char));

    for(i=0;i<n;i++){
        printf("Col: ");
        scanf("%d",&m);
        szData[i]=(char**)malloc(m*sizeof(char));
        for(j=0;j<m;j++){

            printf("string[%d][%d]=",i,j);
            scanf("%s",temp);
            szData[i][j]=(char*)malloc(25*sizeof(char));
            szData[i][j]=temp;

        }
    }


            printf("memmory[%d][%d]=%s\n",0,2,szData[0][2]);//Printing string from specific location


    return 0;
}

Expected structure:

     +----------+----------+----------+----------+
     |    0     |     1    |     2    |    3     |
+----+----------+----------+----------+----------+
| 0  |  string1 |  string2 | string3  |string4   |
+----+----------+----------+----------+--------- +
     +----------+----------+
     |    0     |     1    | 
+----+----------+----------+
| 0  |  string1 |  string2 | 
+----+----------+----------+
     +----------+
     |    0     |      
+----+----------+
| 1  |  string1 |  
+----+----------+
     +----------+----------+----------+----------+
     |    0     |     1    |     2    |    3     |
+----+----------+----------+----------+----------+
| 2  |  string1 |  string2 | string3  |string4   |
+----+----------+----------+----------+--------- +
     +----------+----------+
     |    0     |     1    |     
+----+----------+----------+
| 2  |  string1 |  string2 | 
+----+----------+----------+
     +----------+----------+----------+----------+
     |    0     |     1    |     2    |    3     |
+----+----------+----------+----------+----------+
| 2  |  string1 |  string2 | string3  |string4   |
+----+----------+----------+----------+--------- +
     +----------+----------+
     |    0     |     1    |     
+----+----------+----------+
| 2  |  string1 |  string2 | 
+----+----------+----------+

The code bellow works fine. Why not the above?

#include <stdio,h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char***szData; 
    char temp[25];
    szData= (char *** )malloc(4 * sizeof(char ** )) ;
    szData[0]=(char**)malloc(2*sizeof(char));
    szData[0][0]=(char*)malloc(25*sizeof(char));
    szData[0][0]="Henry\0";
    szData[0][1]=(char*)malloc(25*sizeof(char));
    szData[0][1]="Korir\0";
    szData[1]=(char**)malloc(sizeof(char));
    szData[1][0]=(char*)malloc(25*sizeof(char));
    szData[1][0]="BSc.\0";
    szData[2]=(char**)malloc(3*sizeof(char));
    szData[2][0]=(char*)malloc(25*sizeof(char));
    szData[2][0]="Software Engineering\0";
    szData[2][1]=(char*)malloc(25*sizeof(char));
    szData[2][1]="Kenyatta\0 ";
    szData[2][2]=(char*)malloc(25*sizeof(char));
    szData[2][2]="University\0";
    szData[3]=(char**)malloc(sizeof(char));
    szData[3][0]=(char*)malloc(25*sizeof(char));
    szData[3][0]="From Kipsaiya, Kenya\0";

    printf("szData[%d][%d]=%c size=%d\n",0,1,szData[2][0][0],sizeof(szData[0][1]));
    strcpy(temp,szData[2][0]);
    putchar(szData[0][0][0]);
    printf("temp=%s size=%d\n",temp,sizeof(szData[2][0]));
return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
henrykorir
  • 107
  • 1
  • 12
  • [Possible duplicate](http://stackoverflow.com/questions/35542391/segmentation-fault-but-unable-to-reason-how-memory-allocation-looks-fine-to-me/35542617#35542617) (disclaimer: shameless plug). – n. m. could be an AI Feb 28 '16 at 08:45
  • Hello. Thank you for your contribution.The code crushed amid execution. I would love to see an improvement to the code you supplied. – henrykorir Feb 28 '16 at 13:24

2 Answers2

1

szData[i][j]=temp; right after szData[i][j]=(char*)malloc(25*sizeof(char)); is causing memory leak.

Allocate enough memory and copy the string read.

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

int main(void)
{
    char***szData;
    char temp[500];
    int i,j,k,x,n,m,index;

    printf("Rows:");
    scanf("%d",&n);

    szData=malloc(n*sizeof(char**));

    for(i=0;i<n;i++){
        printf("Col: ");
        scanf("%d",&m);
        szData[i]=malloc(m*sizeof(char*));
        for(j=0;j<m;j++){

            printf("string[%d][%d]=",i,j);
            scanf("%499s",temp);
            szData[i][j]=malloc((strlen(temp)+1)*sizeof(char));
            strcpy(szData[i][j],temp);

        }
    }


    printf("memmory[%d][%d]=%s\n",0,2,szData[0][2]);//Printing string from specific location

    return 0;
}

Note that they say you shouldn't cast the result of malloc() in C.

Community
  • 1
  • 1
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • Hello. Thank you for your contribution.The code crushed amid execution. I would love to see an improvement to the code you supplied. – henrykorir Feb 28 '16 at 13:53
  • It didn't crash in [my test](http://melpon.org/wandbox/permlink/E0719fNj329QNe0Y). What is your input? – MikeCAT Feb 28 '16 at 13:58
  • I used random strings like names. More so, I had to typecast `malloc` for it to compile in my machine. – henrykorir Feb 28 '16 at 15:05
1

These allocations are wrong

szData=(char***)malloc(n*sizeof(char));
                                ^^^^^ 
szData[i]=(char**)malloc(m*sizeof(char));
                                  ^^^^^

There should be

szData=(char***)malloc(n*sizeof(char **));
                                ^^^^^^^ 
szData[i]=(char**)malloc(m*sizeof(char *));
                                  ^^^^^^^

And instead of the assignment

szData[i][j]=temp;

that leads to a memory leak you have to use standard function strcpy

strcpy( szData[i][j], temp );

Also as the number of columns in each row is various then you should somehow to keep the information about the number of columns in a row.

One of approaches is to allocate one more column and set the last column to NULL.

Here is a demonstrative program

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

int main( void ) 
{
    char ***szData;
    unsigned int n, m;
    unsigned int i, j;

    printf( "Rows: " );
    scanf( "%u", &n );

    szData = ( char*** )malloc( n * sizeof( char ** ) );

    for ( i = 0; i < n; i++ )
    {
        printf( "Col: " );
        scanf( "%u", &m );

        szData[i] = ( char ** )calloc( ( m + 1 ), sizeof( char * ) );
        for ( j = 0; j < m; j++ )
        {
            char temp[25];
            printf( "string[%u][%u] = ", i, j );
            scanf( "%24s", temp );
            szData[i][j] = ( char * )malloc( strlen( temp ) + 1 );
            strcpy( szData[i][j], temp );
        }
    }

    printf( "\n" );

    for ( i = 0; i < n; i++ )
    {
        for ( j = 0; szData[i][j] != NULL; j++ ) printf( "%10s", szData[i][j] );
        printf( "\n" );
    }        

    for ( i = 0; i < n; i++ )
    {
        for ( j = 0; szData[i][j] != NULL; j++ ) free( szData[i][j] );;
        free( szData[i] );
    }

    free( szData );             

    return 0;
}

Its output might look like

Rows: 7
Col: 4
string[0][0] = string1
string[0][1] = string2
string[0][2] = string3
string[0][3] = string4
Col: 2
string[1][0] = string1
string[1][1] = string2
Col: 1
string[2][0] = string1
Col: 4
string[3][0] = string1
string[3][1] = string2
string[3][2] = string3
string[3][3] = string4
Col: 2
string[4][0] = string1
string[4][1] = string2
Col: 4
string[5][0] = string1
string[5][1] = string2
string[5][2] = string3
string[5][3] = string4
Col: 2
string[6][0] = string1
string[6][1] = string2

   string1   string2   string3   string4
   string1   string2
   string1
   string1   string2   string3   string4
   string1   string2
   string1   string2   string3   string4
   string1   string2

EDIT: After you updated your question then the code like this

szData[0][0]=(char*)malloc(25*sizeof(char));
szData[0][0]="Henry\0";

is also wrong.

There is at least a memory leak because at first szData[0][0] was assigned with the address of the allocated memory and then in the next statement it was reassigned.

Also there is no need to write string literals like "Henry\0" because string literal "Henry" already has the terminating zero.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335