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 achar [2][10]
. Thats an array of 2 items, where each item is an array of 10 characters. Therefore the pointer should bechar (*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 bechar str[2][10]
, which as parameter "decays" into the equivalentchar (*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 callfree()
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;
}