Return multidimensional char array in C - c

In C, how can I create a function which returns a string array? Or a multidimensional char array?
For example, I want to return an array char paths[20][20] created in a function.
My latest try is
char **GetEnv()
{
int fd;
char buf[1];
char *paths[30];
fd = open("filename" , O_RDONLY);
int n=0;
int c=0;
int f=0;
char tmp[64];
while((ret = read(fd,buf,1))>0)
{
if(f==1)
{
while(buf[0]!=':')
{
tmp[c]=buf[0];
c++;
}
strcpy(paths[n],tmp);
n++;
c=0;
}
if(buf[0] == '=')
f=1;
}
close(fd);
return **paths; //warning: return makes pointer from integer without a cast
//return (char**)paths; warning: function returns address of local variable
}
I tried various 'settings' but each gives some kind of error.
I don't know how C works

You can't safely return a stack-allocated array (using the array[20][20] syntax).
You should create a dynamic array using malloc:
char **array = malloc(20 * sizeof(char *));
int i;
for(i=0; i != 20; ++i) {
array[i] = malloc(20 * sizeof(char));
}
Then returning array works

You should just return array (return array;). the ** after declaration are used for dereferencing.
Also, make sure the the memory for this array is allocated on the heap (using malloc or simillar function)

Related

Why strcpy crashes? [duplicate]

is that even possible?
Let's say that I want to return an array of two characters
char arr[2];
arr[0] = 'c';
arr[1] = 'a';
from a function. What type do I even use for the function? Is my only choice to use pointers and void the function? So far I've tried having a char* function or a char[]. Apparently you can only have functions of char(*[]). The only reason I want to avoid using pointers is the fact that the function has to end when it encounters a "return something;" because the value of "something" is a character array (not a string!) that might change size depending on the values I pass into the function through the main function. Thanks to anyone who responds in advance.
You've got several options:
1) Allocate your array on the heap using malloc(), and return a pointer to it. You'll also need to keep track of the length yourself:
void give_me_some_chars(char **arr, size_t *arr_len)
{
/* This function knows the array will be of length 2 */
char *result = malloc(2);
if (result) {
result[0] = 'c';
result[1] = 'a';
}
/* Set output parameters */
*arr = result;
*arr_len = 2;
}
void test(void)
{
char *ar;
size_t ar_len;
int i;
give_me_some_chars(&ar, &ar_len);
if (ar) {
printf("Array:\n");
for (i=0; i<ar_len; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
free(ar);
}
}
2) Allocate space for the array on the stack of the caller, and let the called function populate it:
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
/* Returns the number of items populated, or -1 if not enough space */
int give_me_some_chars(char *arr, int arr_len)
{
if (arr_len < 2)
return -1;
arr[0] = 'c';
arr[1] = 'a';
return 2;
}
void test(void)
{
char ar[2];
int num_items;
num_items = give_me_some_chars(ar, ARRAY_LEN(ar));
printf("Array:\n");
for (i=0; i<num_items; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
}
DO NOT TRY TO DO THIS
char* bad_bad_bad_bad(void)
{
char result[2]; /* This is allocated on the stack of this function
and is no longer valid after this function returns */
result[0] = 'c';
result[1] = 'a';
return result; /* BAD! */
}
void test(void)
{
char *arr = bad_bad_bad_bad();
/* arr is an invalid pointer! */
}
Since you have a predetermined size of you array you can in-fact return the array if you wrap it with a struct:
struct wrap
{
char a[2] ;
} ;
struct wrap Get( void )
{
struct wrap w = { 0 } ;
w.a[0] = 'c';
w.a[1] = 'a';
return w ;
}
You can return a pointer for the array from a function, however you can't return pointers to local arrays, the reference will be lost.
So you have 3 options:
Use a global variable:
char arr[2];
char * my_func(void){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Use dynamic allocation (the caller will have the responsibility to free the pointer after using it; make that clear in your documentation)
char * my_func(void){
char *arr;
arr = malloc(2);
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Make the caller allocate the array and use it as a reference (my recommendation)
void my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
}
If you really need the function to return the array, you can return the same reference as:
char * my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
You can pass the array to the function and let the function modify it, like this
void function(char *array)
{
array[0] = 'c';
array[1] = 'a';
}
and then
char array[2];
function(array);
printf("%c%c\n", array[0], array[1]);
If you want it as a return value, you should use dynamic memroy allocation,
char *function(void)
{
char *array;
array = malloc(2);
if (array == NULL)
return NULL;
array[0] = 'c';
array[1] = 'a';
return array;
}
then
char *array = function();
printf("%c%c\n", array[0], array[1]);
/* done using `array' so free it because you `malloc'ed it*/
free(array);
Important Note:
You should be aware of the fact that the array as filled above is not a string, so you can't for instance do this
printf("%s\n", array);
because the "%s" expects a matching string to be passed, and in c an array is not a string unless it's last character is '\0', so for a 2 character string you need to allocate space for 3 characters and set the last one to '\0'.
char* getCharArray()
{
return "ca";
}
This works perfecly:
int comm_read_data(int file_i2c, unsigned char** buffer)
{
*buffer = malloc(BUFFER_SIZE);
if (i2c_read_bytes(file_i2c, *buffer, BUFFER_SIZE) != 0)
{
return -1;
}
return BUFFER_SIZE;
}
And then call the function:
unsigned char* buffer;
int length = comm_read_data(file_i2c, &buffer);
/* parse the buffer here */
free(buffer);

How can I free memory and at the same time return a pointer?

I have these functions
char *hash(char *stringa, char *tipohash) {
if (strcmp(tipohash, "md5") == 0) {
stringa = md5(stringa);
}
return stringa;
}
char *md5(char *stringa) {
unsigned char risultato[MD5_DIGEST_LENGTH];
int i;
char *hashfinale = malloc(sizeof(char) * MD5_DIGEST_LENGTH * 2);
MD5((const unsigned char *)stringa, strlen(stringa), risultato);
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(hashfinale + 2 * i, "%02x", risultato[i]);
}
return (char *)hashfinale;
}
How I can return (char *)hashfinale doing the free without losing the value of the string?
This is the caller
char *hashlinea = hash(stringa, hashType);
There are basically two ways to solve the problem, and none of them involves your code calling free.
The first way is to just do nothing different from now, except to add documentation so the user of your hash function knows that the code must call free on the returned pointer:
// This is the code using your function
char *hashlinea = hash(stringa,hashType);
// Some code using hashlinea
free(hashlinea);
The second way is to pass a pointer to an existing array, and your code use that array instead of allocating it using malloc:
char hashlinea[MD5_DIGEST_LENGTH*2];
hash(stringa, hashType, hashlinea);
For this your hash function needs to pass on the third argument to the md5 function, which should use it instead of allocating memory:
char *md5(char *stringa, char *hashfinale){
unsigned char risultato[MD5_DIGEST_LENGTH];
int i;
// No memory allocation here
MD5((const unsigned char *)stringa, strlen(stringa), risultato);
for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(hashfinale + 2*i,"%02x",risultato[i]);
}
return hashfinale;
}
It is not possible. IMO it is better to pass the pointer to the buffer. The caller will be responsible for the memory management
char *md5(char *stringa, char *hashfinale){
...
}
There is a problem in your md5 function: the size allocated for the MD5 hash must be one byte longer for the null terminator:
char *hashfinale = malloc(sizeof(char) * (MD5_DIGEST_LENGTH * 2 + 1));
Note that in C (and C++) sizeof(char) is 1 by definition, so you could just write:
char *hashfinale = malloc(MD5_DIGEST_LENGTH * 2 + 1);
Regarding your question, hash returns either its argument or an allocated object. This is a problem for memory management, as yo may not know later in the program if the return value must be freed or not. Passing the destination array for the hash string is a better alternative, otherwise you should duplicate the string so the return value of hash can be unconditionally freed:
char *md5(const char *stringa) {
unsigned char risultato[MD5_DIGEST_LENGTH];
int i;
char *hashfinale = malloc(MD5_DIGEST_LENGTH * 2 + 1);
MD5((const unsigned char *)stringa, strlen(stringa), risultato);
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(hashfinale + 2 * i, "%02x", risultato[i]);
}
return hashfinale;
}
// always free the return value
char *hash(const char *stringa, const char *tipohash) {
if (!strcmp(tipohash, "md5")) {
return md5(stringa);
} else {
return strdup(stringa);
}
}

Passing Character Array to Function and Return Character Array [duplicate]

is that even possible?
Let's say that I want to return an array of two characters
char arr[2];
arr[0] = 'c';
arr[1] = 'a';
from a function. What type do I even use for the function? Is my only choice to use pointers and void the function? So far I've tried having a char* function or a char[]. Apparently you can only have functions of char(*[]). The only reason I want to avoid using pointers is the fact that the function has to end when it encounters a "return something;" because the value of "something" is a character array (not a string!) that might change size depending on the values I pass into the function through the main function. Thanks to anyone who responds in advance.
You've got several options:
1) Allocate your array on the heap using malloc(), and return a pointer to it. You'll also need to keep track of the length yourself:
void give_me_some_chars(char **arr, size_t *arr_len)
{
/* This function knows the array will be of length 2 */
char *result = malloc(2);
if (result) {
result[0] = 'c';
result[1] = 'a';
}
/* Set output parameters */
*arr = result;
*arr_len = 2;
}
void test(void)
{
char *ar;
size_t ar_len;
int i;
give_me_some_chars(&ar, &ar_len);
if (ar) {
printf("Array:\n");
for (i=0; i<ar_len; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
free(ar);
}
}
2) Allocate space for the array on the stack of the caller, and let the called function populate it:
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
/* Returns the number of items populated, or -1 if not enough space */
int give_me_some_chars(char *arr, int arr_len)
{
if (arr_len < 2)
return -1;
arr[0] = 'c';
arr[1] = 'a';
return 2;
}
void test(void)
{
char ar[2];
int num_items;
num_items = give_me_some_chars(ar, ARRAY_LEN(ar));
printf("Array:\n");
for (i=0; i<num_items; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
}
DO NOT TRY TO DO THIS
char* bad_bad_bad_bad(void)
{
char result[2]; /* This is allocated on the stack of this function
and is no longer valid after this function returns */
result[0] = 'c';
result[1] = 'a';
return result; /* BAD! */
}
void test(void)
{
char *arr = bad_bad_bad_bad();
/* arr is an invalid pointer! */
}
Since you have a predetermined size of you array you can in-fact return the array if you wrap it with a struct:
struct wrap
{
char a[2] ;
} ;
struct wrap Get( void )
{
struct wrap w = { 0 } ;
w.a[0] = 'c';
w.a[1] = 'a';
return w ;
}
You can return a pointer for the array from a function, however you can't return pointers to local arrays, the reference will be lost.
So you have 3 options:
Use a global variable:
char arr[2];
char * my_func(void){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Use dynamic allocation (the caller will have the responsibility to free the pointer after using it; make that clear in your documentation)
char * my_func(void){
char *arr;
arr = malloc(2);
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Make the caller allocate the array and use it as a reference (my recommendation)
void my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
}
If you really need the function to return the array, you can return the same reference as:
char * my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
You can pass the array to the function and let the function modify it, like this
void function(char *array)
{
array[0] = 'c';
array[1] = 'a';
}
and then
char array[2];
function(array);
printf("%c%c\n", array[0], array[1]);
If you want it as a return value, you should use dynamic memroy allocation,
char *function(void)
{
char *array;
array = malloc(2);
if (array == NULL)
return NULL;
array[0] = 'c';
array[1] = 'a';
return array;
}
then
char *array = function();
printf("%c%c\n", array[0], array[1]);
/* done using `array' so free it because you `malloc'ed it*/
free(array);
Important Note:
You should be aware of the fact that the array as filled above is not a string, so you can't for instance do this
printf("%s\n", array);
because the "%s" expects a matching string to be passed, and in c an array is not a string unless it's last character is '\0', so for a 2 character string you need to allocate space for 3 characters and set the last one to '\0'.
char* getCharArray()
{
return "ca";
}
This works perfecly:
int comm_read_data(int file_i2c, unsigned char** buffer)
{
*buffer = malloc(BUFFER_SIZE);
if (i2c_read_bytes(file_i2c, *buffer, BUFFER_SIZE) != 0)
{
return -1;
}
return BUFFER_SIZE;
}
And then call the function:
unsigned char* buffer;
int length = comm_read_data(file_i2c, &buffer);
/* parse the buffer here */
free(buffer);

How can I return a character array from a function in C?

is that even possible?
Let's say that I want to return an array of two characters
char arr[2];
arr[0] = 'c';
arr[1] = 'a';
from a function. What type do I even use for the function? Is my only choice to use pointers and void the function? So far I've tried having a char* function or a char[]. Apparently you can only have functions of char(*[]). The only reason I want to avoid using pointers is the fact that the function has to end when it encounters a "return something;" because the value of "something" is a character array (not a string!) that might change size depending on the values I pass into the function through the main function. Thanks to anyone who responds in advance.
You've got several options:
1) Allocate your array on the heap using malloc(), and return a pointer to it. You'll also need to keep track of the length yourself:
void give_me_some_chars(char **arr, size_t *arr_len)
{
/* This function knows the array will be of length 2 */
char *result = malloc(2);
if (result) {
result[0] = 'c';
result[1] = 'a';
}
/* Set output parameters */
*arr = result;
*arr_len = 2;
}
void test(void)
{
char *ar;
size_t ar_len;
int i;
give_me_some_chars(&ar, &ar_len);
if (ar) {
printf("Array:\n");
for (i=0; i<ar_len; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
free(ar);
}
}
2) Allocate space for the array on the stack of the caller, and let the called function populate it:
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
/* Returns the number of items populated, or -1 if not enough space */
int give_me_some_chars(char *arr, int arr_len)
{
if (arr_len < 2)
return -1;
arr[0] = 'c';
arr[1] = 'a';
return 2;
}
void test(void)
{
char ar[2];
int num_items;
num_items = give_me_some_chars(ar, ARRAY_LEN(ar));
printf("Array:\n");
for (i=0; i<num_items; i++) {
printf(" [%d] = %c\n", i, ar[i]);
}
}
DO NOT TRY TO DO THIS
char* bad_bad_bad_bad(void)
{
char result[2]; /* This is allocated on the stack of this function
and is no longer valid after this function returns */
result[0] = 'c';
result[1] = 'a';
return result; /* BAD! */
}
void test(void)
{
char *arr = bad_bad_bad_bad();
/* arr is an invalid pointer! */
}
Since you have a predetermined size of you array you can in-fact return the array if you wrap it with a struct:
struct wrap
{
char a[2] ;
} ;
struct wrap Get( void )
{
struct wrap w = { 0 } ;
w.a[0] = 'c';
w.a[1] = 'a';
return w ;
}
You can return a pointer for the array from a function, however you can't return pointers to local arrays, the reference will be lost.
So you have 3 options:
Use a global variable:
char arr[2];
char * my_func(void){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Use dynamic allocation (the caller will have the responsibility to free the pointer after using it; make that clear in your documentation)
char * my_func(void){
char *arr;
arr = malloc(2);
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
Make the caller allocate the array and use it as a reference (my recommendation)
void my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
}
If you really need the function to return the array, you can return the same reference as:
char * my_func(char * arr){
arr[0] = 'c';
arr[1] = 'a';
return arr;
}
You can pass the array to the function and let the function modify it, like this
void function(char *array)
{
array[0] = 'c';
array[1] = 'a';
}
and then
char array[2];
function(array);
printf("%c%c\n", array[0], array[1]);
If you want it as a return value, you should use dynamic memroy allocation,
char *function(void)
{
char *array;
array = malloc(2);
if (array == NULL)
return NULL;
array[0] = 'c';
array[1] = 'a';
return array;
}
then
char *array = function();
printf("%c%c\n", array[0], array[1]);
/* done using `array' so free it because you `malloc'ed it*/
free(array);
Important Note:
You should be aware of the fact that the array as filled above is not a string, so you can't for instance do this
printf("%s\n", array);
because the "%s" expects a matching string to be passed, and in c an array is not a string unless it's last character is '\0', so for a 2 character string you need to allocate space for 3 characters and set the last one to '\0'.
char* getCharArray()
{
return "ca";
}
This works perfecly:
int comm_read_data(int file_i2c, unsigned char** buffer)
{
*buffer = malloc(BUFFER_SIZE);
if (i2c_read_bytes(file_i2c, *buffer, BUFFER_SIZE) != 0)
{
return -1;
}
return BUFFER_SIZE;
}
And then call the function:
unsigned char* buffer;
int length = comm_read_data(file_i2c, &buffer);
/* parse the buffer here */
free(buffer);

Char * (pointer) function

I need to pass in a char * in a function and have it set to a cstring value. I can properly set it as a string in the function, but it doesn't seem to print out correctly in the function that called the char * function in the first place.
int l2_read(char *chunk,int length)
{
chunk = malloc( sizeof(char) * length);
int i;
for(i = 0; i < length; i++){
char c;
if(read(&c) < 0) return (-1); // this gets a single character
chunk[i] = c;
}
printf("%s",chunk); // this prints fine
return 1;
}
// main
char *string;
int value = l2_read(string,16);
printf("%s",chunk); // prints wrong
In C, everything is passed by value. A general rule to remember is, you can't change the value of a parameter passed to a function. If you want to pass something that needs to change, you need to pass a pointer to it.
So, in your function, you want to change chunk. chunk is char *. To be able to change the value of the char *, you need to pass a pointer to that, i.e., char **.
int l2_read(char **chunkp, int length)
{
int i;
*chunkp = malloc(length * sizeof **chunkp);
if (*chunkp == NULL) {
return -2;
}
for(i = 0; i < length; i++) {
char c;
if (read(&c) < 0) return -1;
(*chunkp)[i] = c;
}
printf("%s", *chunkp);
return 1;
}
and then in main():
char *string;
int value = l2_read(&string, 16);
if (value == 1) {
printf("%s", string); /* corrected typo */
free(string); /* caller has to call free() */
} else if (value == -2) {
/* malloc failed, handle error */
} else {
/* read failed */
free(string);
}
Pass-by-value in C is the reason why strtol(), strtod(), etc., need char **endptr parameter instead of char *endptr—they want to be able to set the char * value to the address of the first invalid char, and the only way they can affect a char * in the caller is to receive a pointer to it, i.e., receive a char *. Similarly, in your function, you want to be able to change a char * value, which means you need a pointer to a char *.
Hope that helps.
I just re-read your question.
You seem to have been hit by the pass by value, even if it is a pointer, problem. Also, is chunk null terminated?
You have to pass a pointer to a pointer.
int l2_read(char **chunk,int length)
{
*chunk = malloc( sizeof(char) * length);
int i;
for(i = 0; i < length; i++)
{
char c;
if (read(&c) < 0) return (-1);
(*chunk)[i] = c;
}
printf("%s",*chunk);
return 1;
}
char *string;
int value = l2_read(&string,16);
printf("%s",string);
I totally agree with the answer posted above. You are essentially modifying the value of pointer so you need to pass the reference of pointer. use char ** instead of char*.

Resources