Home > OS >  array of pointers pointing to spaces allocated in calling function and write in called function
array of pointers pointing to spaces allocated in calling function and write in called function

Time:10-15

I have this code in func I am getting pointer to array of pointers. The purpose of this function is to write strings to two allocated spaces for chars. Allocated in main. I am getting segFault at this line

memcpy(*c[1],"hi",sizeof("hi"));

this is full code

void func(char (**c)[])
{
  memcpy(*c[0],"hello",sizeof("hel"));
  memcpy(*c[1],"hi",sizeof("hi"));
}

int main()
{
  char (*arr)[2]=malloc(sizeof(char[2][10]));
  func(&arr);
  printf("%s\n",arr[0]);
  printf("%s\n", arr[1]);
  return 0;
}

I have allocated the array of pointers using

char (*arr)[2]=malloc(sizeof(char[2][10]));

now to pass the address of two allocated string spaces I am calling like this

func(&arr);

the point of passing the address of array of pointers variable arr so I can see the changes to string spaces in main(...) , CHANGES THAT MADE IN FUNC

but this line causing trouble

memcpy(*c[1],"hi",sizeof("hi"));

segFault

Can anyone please inform me what I am doing wrong this answer is also related to array of pointers. https://stackoverflow.com/a/69551741/4808760

Output I am expecting is

hell
hi

Valgrind dump

valgrind --leak-check=full -s ./a.out 
==7397== Memcheck, a memory error detector
==7397== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7397== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==7397== Command: ./a.out
==7397== 
==7397== Invalid write of size 2
==7397==    at 0x4849F23: memcpy@GLIBC_2.2.5 (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==7397==    by 0x1091F2: func (test.c:8)
==7397==    by 0x10922A: main (test.c:18)
==7397==  Address 0x54698dcdde89a700 is not stack'd, malloc'd or (recently) free'd
==7397== 
==7397== 
==7397== Process terminating with default action of signal 11 (SIGSEGV)
==7397==  General Protection Fault
==7397==    at 0x4849F23: memcpy@GLIBC_2.2.5 (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==7397==    by 0x1091F2: func (test.c:8)
==7397==    by 0x10922A: main (test.c:18)
==7397== 
==7397== HEAP SUMMARY:
==7397==     in use at exit: 30 bytes in 1 blocks
==7397==   total heap usage: 1 allocs, 0 frees, 30 bytes allocated
==7397== 
==7397== LEAK SUMMARY:
==7397==    definitely lost: 0 bytes in 0 blocks
==7397==    indirectly lost: 0 bytes in 0 blocks
==7397==      possibly lost: 0 bytes in 0 blocks
==7397==    still reachable: 30 bytes in 1 blocks
==7397==         suppressed: 0 bytes in 0 blocks
==7397== Reachable blocks (those to which a pointer was found) are not shown.
==7397== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==7397== 
==7397== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==7397== 
==7397== 1 errors in context 1 of 1:
==7397== Invalid write of size 2
==7397==    at 0x4849F23: memcpy@GLIBC_2.2.5 (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==7397==    by 0x1091F2: func (test.c:8)
==7397==    by 0x10922A: main (test.c:18)
==7397==  Address 0x54698dcdde89a700 is not stack'd, malloc'd or (recently) free'd
==7397== 
==7397== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

CodePudding user response:

One way would be:

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

void func(char **c)
{
    c[0] = malloc(strlen("hel")   1);
    c[1] = malloc(strlen("hi")   1);
    strcpy(c[0], "hel");
    strcpy(c[1], "hi");
}

int main()
{
  char *arr[2];
  func(arr);
  printf("%s\n",arr[0]);
  printf("%s\n", arr[1]);
  return 0;
}

Here, arr is an array of two pointers to char. When we pass an array to a function, it decays to a pointer to the first element. Hence, func() accepts a pointer to a pointer to a char. c[0] and c[1] will hold the addresses returned by malloc() to those offsets inside c. Then, strcpy() just copies over the passed string to the allocated space. When this function returns, main() finds that data has already been placed inside arr[0] and arr[1].

Optionally, you could also call strdup() in func(). Also, do not forget to call free().

CodePudding user response:

To address what's actually wrong with your code:

  • You don't include the relevant headers.
  • char (*arr)[2] is wrong. You want this to point at the first item of a char [2][10]. Thats an array of 2 items, where each item is an array of 10 characters. Therefore the pointer should be char (*arr)[10].
  • func(&arr); doesn't make sense, there's no reason to pass a pointer by reference unless you intend to change the pointer itself (like when doing malloc inside a function).
  • char (**c)[] is nonsense. This is a pointer to an array of pointers to incomplete array type. But you can't pass an incomplete array type as parameter to a function. This should be char str[2][10], which as parameter "decays" into the equivalent char (*str)[10].
  • You can't use memcpy on substrings, because it doesn't append nul termination. If you use memcpy, then you must manually add a \0 at the end. Note that malloc (unlike calloc) doesn't zero-init the allocated memory.
  • You forgot to call free(). Yes, the OS will deallocate the memory but you should still call free() explicitly, since that increases the chance of exposing heap corruption/pointer/memory leak bugs early on at the design stage.

Corrected code:

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

void func(char str[2][10])
{
  strcpy(str[0],"hello");
  strcpy(str[1],"hi");
}

int main (void)
{
  char (*arr)[10]=malloc(sizeof(char[2][10]));
  func(arr);
  printf("%s\n",arr[0]);
  printf("%s\n", arr[1]);
  free(arr);
  return 0;
}

CodePudding user response:

In this statement

char (*arr)[2]=malloc(sizeof(char[2][10]));

arr is a pointer to an array of 2 characters. Whereas, you are allocating it memory of 2 array of 10 characters. It should be

char (*arr)[10] = malloc(sizeof(char[2][10]));
           ^^^^

The type of &arr is char (**)[10], so the type of func() function parameter should be char (**)[10]

void func(char (**c)[10])
                    ^^^^

In func() function, you should access first and second array like (*c)[0] and (*c)[1] respectively.

Output I am expecting is

hell

You are giving count of characters, to copy, to memcpy() as sizeof("hel"). Do you want output hell or hel? I believe (or assume), you want first 3 characters of string literal "hello" to copy to (*c)[0].

Note that sizeof("hel") will give output 4 because it includes null terminator character as well. So, memcpy() will copy 4 characters from string literal "hello". If you want to copy first 3 character from string "hello" then you should pass the count as sizeof("hel") - 1.

Also, you should append the null terminator character after copying characters using memcpy() as memcpy() does not append terminating null character automatically. You can do something like this:

  memcpy((*c)[0],"hello",sizeof("hel") - 1);
  (*c)[0][sizeof("hel") - 1] = '\0';    // append null terminator character 

Last, follow good programming practice, always check the malloc() return and make sure to free() the dynamically allocated memory once you done with it.

Putting these altogether, you can do:

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

void func(char (**c)[10]) {
    memcpy((*c)[0], "hello", sizeof("hel") - 1);
    (*c)[0][sizeof("hel") - 1] = '\0';
    memcpy((*c)[1], "hi", sizeof("hi") - 1);
    (*c)[1][sizeof("hi") - 1] = '\0';
}

int main(void) {
    char (*arr)[10] = malloc(sizeof(char[2][10]));
    if (arr == NULL) {
        fprintf (stderr, "Failed to allocate memory\n");
        exit(EXIT_FAILURE);
    }

    func(&arr);
    printf("%s\n", arr[0]);
    printf("%s\n", arr[1]);

    free(arr);
    return 0;
}

Output:

# ./a.out
hel
hi

the point of passing the address of array of pointers variable arr so I can see the changes to string spaces in main(...)

Since, you are allocating the memory to arr pointer in main() function before calling func() function, you don't need to pass the address of arr to reflect the changes to string space in main() function after returning from func() function. Simply pass the arr to func() function. When you pass arr, that means, you are passing the pointer to allocated memory to func() function, hence, whatever will be written to that memory in func() will reflect in main(). You also need to change the type of func() parameter and make it same as type of arr which is char (*)[10] and access the first and second array like c[0] and c[1] respectively. You can do

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

void func(char (*c)[10]) {
    memcpy(c[0], "hello", sizeof("hel") - 1);
    c[0][sizeof("hel") - 1] = '\0';
    memcpy(c[1], "hi", sizeof("hi") - 1);
    c[1][sizeof("hi") - 1] = '\0';
}

int main(void) {
    char (*arr)[10] = malloc(sizeof(char[2][10]));
    if (arr == NULL) {
        fprintf (stderr, "Failed to allocate memory\n");
        exit(EXIT_FAILURE);
    }

    func(arr);
    printf("%s\n", arr[0]);
    printf("%s\n", arr[1]);

    free(arr);
    return 0;
}

CodePudding user response:

Thanks for the answer I got from babon.

I can also allocate the spaces in main or if I am in need to creating spaces in one line then this would be it char (*arr)[2]=malloc(sizeof(char[2][2])) but I did not get the answer how to pass and assign data to that in either main or called function in linked answer. just told me how to allocate it

void func(char **c)
{
  memcpy(c[0],"hello",sizeof("hel"));
  memcpy(c[1],"hi",sizeof("hi"));
//  memcpy(*c[2],"hell",sizeof("hell"));
//  c[0]="hello";
  //c[1]="hi";
}

int main()
{
  char *arr[2];
  arr[0]=malloc(sizeof(char[2][10]));
  arr[1]=malloc(sizeof(char[2][10]));

  func(arr);
  printf("%s\n",arr[0]);
  printf("%s\n", arr[1]);

  return 0;
}
  •  Tags:  
  • c
  • Related