-2

I am trying to pass a pointer to an array of char pointers to a function, where i want to initialize it.

However, my implementation produces a segmentation fault and I can't figure out why. Can anyone help?

Here's my code:

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

void ret_2darr(char *(*str)[5])
{
    int i,j;
    for(i=0;i<3;i++)
    {
        for(j=0;j<=5;j++)
        {
            str[i][j]=(char *)malloc(sizeof("sach"));
            strcpy(str[i][j],"sach");
        }
    }
}

main()
{
    char *(*a)[5]=NULL;
    ret_2darr(a);
    int i,j;
    for(i=0;i<3;i++)
    {
        for(j=0;j<=5;j++)
        {
            printf("%s",a[i][j]);
        }
    }
 }
moooeeeep
  • 31,622
  • 22
  • 98
  • 187

3 Answers3

2

Consider this trivial code:

int a = 0;
func(a);
...

void func (int x)
{
  x = 5;
}

This code does not modify the variable a, because the function only modified a copy of the variable, rather than the actual contents of it.

Pointers or array pointers are no different, if you assign a pointer passed as parameter to point somewhere else, that assignment is only valid within that function. So you will have to pass an address to the pointer. This is the main mistake: the function will only create a memory leak as you only had a temporary pointer pointing at the allocated memory, which is forgotten as soon as the function returns.

So you will have to pass the array pointer by address... which is the real tricky part. Your options are either passing a pointer to an array pointer, or returning an array pointer. Either will produce some seriously evil C code:

 void ret_2darr(char *(**str)[5]) // pass array pointer by reference

or

 char* (*(*ret_2darr)(void))[5]; // return array pointer from function

Don't write code like that though! It is an unreadable mess. typedef is the only sane solution here. For example:

typedef char* arr_t[5];  // the array type
arr_t* ptr; // a pointer to that array type

Other bugs:

  • You actually never allocate the array of pointers anywhere, you just start to allocate items of the array without allocating the array itself existing.

  • You seem to want a 2D array, but you are using a 1D array type. The array pointer should have been char *(*a)[3][5].

  • You access the array pointer incorrectly. str[i][j] means "in array number [i], give me sub-array [j]", where you rather wanted "in my 2D array of char*, give me item [i][j]". Again, make up your mind about how many dimensions you should have.

  • You loop over 6 indexes not 5 etc.


I would strongly suggest just to forget about array pointers entirely, at least as far as that function is concerned. Leave the allocation of the actual 2D array to the caller. Use char* arr[3][5] as function parameter instead.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

consulting with debugger, it says :

$ gcc -g test.c -o test
$ gdb ./test 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...done.
(gdb) run
Starting program: /home/xand/code/stackoverflow/c/test 

Program received signal SIGSEGV, Segmentation fault.
0x000000000040064a in ret_2darr (str=0x0) at test.c:26
26        str[i][j]=(char *)malloc(sizeof("sach"));
(gdb) print str
$1 = (char *(*)[5]) 0x0

which means in ret_2darr when you try to access str it is null. null dereferencing is causing the segfault..

looking back at how str is defined and used :

char *(*a)[5]=NULL;

we see that it is a char **[5] ( this is the start of the problem ).

Since we only need to store an five strings, this should be as a char *[5].

correcting this and flow on issues gives

other fixes

  • corrected main prototype and added flow on return 0..
  • redefined a properly
  • corrected bounds error <=5 goes to < 5 ( two times )
  • removed malloc cast as redundant
  • added \n for proper printing..
  • added free(a[j]) to cleanup memory
  • handle allocation errors from malloc

adjusted code

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

int ret_2darr(char *a[5]);

int main(void)
{
  char *a[5];
  if(ret_2darr(a))
  {
    // handle/log allocation errors here..
    return 0;
  }
  int i,j;
  for(j=0;j<5;j++)
  {
    printf("%s\n",a[j]);
    free(a[j]);
  }
  return 0;
}

int ret_2darr(char *str[5])
{
  int j;
  memset(str, 5*sizeof(char *), 0);
  for(j=0;j<5;j++)
  {
    str[j]=malloc(sizeof("sach"));
    if(!str[j])goto err0;
    strcpy(str[j],"sach");
  }
  return 0;

err0:
  for(;j>=0;j--)
  {
    if(str[j])free(str[j]);
  }
  return 1;
}

output

$ gcc -g test.c.fixed.c -o test
$ valgrind ./test
==18525== Memcheck, a memory error detector
==18525== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==18525== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==18525== Command: ./test
==18525== 
sach
sach
sach
sach
sach
==18525== 
==18525== HEAP SUMMARY:
==18525==     in use at exit: 0 bytes in 0 blocks
==18525==   total heap usage: 5 allocs, 5 frees, 25 bytes allocated
==18525== 
==18525== All heap blocks were freed -- no leaks are possible
==18525== 
==18525== For counts of detected and suppressed errors, rerun with: -v
==18525== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

reference

Community
  • 1
  • 1
amdixon
  • 3,814
  • 8
  • 25
  • 34
  • " we see that it is a char *** ( this is the start of the problem ). Since we only need to store an array of strings, this should be as a char ** ". Huh, what? This is nonsense. A 2D array is not a pointer-to-pointer nor are they compatible. Please correct, as I don't want to down vote an otherwise good answer. – Lundin Sep 28 '15 at 11:23
-1

In line no.7 it should be char *(*a)[5]; No need of defining varible a with NULL.

Naveen.sn
  • 72
  • 6
  • If you compile qwith gcc -Wall option it will give you: warning: ‘a’ is used uninitialized in this function [-Wuninitialized] – LPs Sep 28 '15 at 10:05
  • And what about all other error: `sizeof("sach")` is not enough to strore that string, and so on.... – LPs Sep 28 '15 at 10:07
  • @LPs: I executed above code with gcc -Wall its not throwing any error for sizeof function. Its giving correct output. Correct me if i am wrong... – Naveen.sn Sep 28 '15 at 10:47
  • It not trigger a warning, because of it is a string literal. The right way to have a string length is `strlen` function. – LPs Sep 28 '15 at 11:27