need help in understanding passing char* [] to function - c

I am trying to pass a array of pointers to string to a function where I need to set the values. In the passing function I do not know the number of strings I will get, the called function is calling some other function which returns list of strings.
Sample code below:
int main() {
char** list;
create(list);
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char*));
strcpy(*(array + i), str[i]);
i++;
}
return 1;
}
This gives me segmentation fault.
What wrong am I doing here. Please help.
Thanks
EDIT
Updated code from below comments:
int main() {
char** list;
create(list);
int i = 0;
for (i = 0; i < 2; i++) {
printf("%s\n", list[i]); // segmentation fault
}
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char));
strcpy(*(array + i), str[i]);
printf("%s\n", array[i]); // this prints
}
return 1;
}
Now getting segmentation fault in main while printing the list.
Actual code where I am reading the strings
int i;
for ( i=0; i<reply->elements; i++ )
{
printf( "Result: %d---%s\n", i,reply->element[i]->str );
*array[i] = (char*)malloc(strlen(reply->element[i]->str));
printf("***");
strcpy(array[i],reply->element[i]->str);
printf( "Array[%d]: %s\n", i,array[i] );
}

You correctly alloc memory for the individual strings, but fail to alloc some for the array itself.
You should use:
int main() {
char* list[8] = {0}; /* initialize pointers to NULL */
create(list);
/* free allocated memory - free(NULL) is legal and is a noop */
for (i=0; i<sizeof(list)/sizeof(list[0]); i++) free(list[i]);
return 0; /* never return random value from main */
}
And you should remove the i++ at the end of the loop in function create because it leads to a double increment.
Alternatively you could alloc the array itself in the function create:
int create(char ***array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
*array = malloc(1 + sizeof(str)/sizeof(str[0]));
for (i = 0; i < 2; i++) {
len = strlen(str[i]) + 1;
printf("%d\n", len);
(*array)[i] = malloc(len * sizeof(char*));
strcpy((*array)[i], str[i]);
}
(*array)[i] = NULL;
return i;
}
int main() {
char** list;
create(&list);
}
In above code, the length of the array is the return value from create, and the last element of list is a NULL (in the same logic as argc/argv).

You need to allocate some space for list or undefined behavior occurs:
char* list[2];
You increment i twice; therefore, remove the i++ from the bottom of the for loop.
Minor notes:
refer to string literals as const char*
use array[i] instead of *(array + i)
don't cast the result of malloc
malloc allocates too much space as you allocate len char*s, even though you need just chars. Also, as #CoolGuy noted, you need one extra byte for the null byte. Replace the allocation with
array[i] = malloc(len * sizeof(char) + sizeof(char));
or
array[i] = malloc(len + 1);
call free after malloc
you assign 0 twice to i; remove the initialization

You allocate two arrays (char*) to store the strings "hello" and "dear" but does not allocate the array (char**) containing those two string array.

I would suggest you to change declaration of function create to this -
int create(char ***array);
And call it like this -
create(&list);
In function create allocate memory like this -
*array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++)
{
len = strlen(str[i]);
printf("%d\n", len);
(*array)[i] =malloc(len * sizeof(char*)+1);
strcpy((*array)[i], str[i]);
}
And do the printing as you do in main.
Note - free memory that you allocate.
And you should declare len as type size_t -> size_t len;
and print it with %zu specifier in printf .
See working code here -https://ideone.com/GX2k9T

Related

Loop of sprintf only outputing final looped value

I have an char* array. I loop through the correct index of the array to put numbers.
However, it seems that the value placed in the index is wrong. It seems to only store the last call to sprintf.
For instance, if I want the numbers 0, 1, 2, 3. However, it seems to return 3, 3, 3, 3.
I have placed a printf statement to see if there is an error, but it produces the correct numbers. I assume there must be a weird error when using sprintf with an array.
char* printArray[12];
for (int i = 1; i < 12+1; i++) {
char *printVal;
char temp[10];
sprintf(temp, "%d", i-1);
printVal = temp;
printf("%s\n", printVal);
printArray[i-1] = printVal;
}
for (int i = 0; i < 12; i++) {
printf("%s\n", printArray[i]);
}
This is a simplified version. This produces the error.
I have attempted to use strcpy but that results in the same error.
The problem is that the memory for temp goes away when you leave each iteration of the for loop, so you can't save pointers to temp into printArray.
You need to make a dynamic copy of temp so you can save it outside the loop.
printArray should be an array of strings, not pointers, then you can use strcpy() to copy them.
char *printArray[12];
for (int i = 1; i < 12+1; i++) {
char temp[10];
sprintf(temp, "%d", i-1);
printf("%s\n", temp);
printArray[i-1] = strdup(temp);
}
for (int i = 0; i < 12; i++) {
printf("%s\n", printArray[i]);
}
If you don't have strdup() available, it's simple:
char *my_strdup(const char *s) {
char *new = malloc(strlen(s)+1);
if (new) {
strcpy(new, s);
}
return new;
}
Undefined behavior (UB)
printArray[i-1] = printVal; repeatedly assigns the address of local object char temp[10];.
Later code attempts to print the data in this common, now invalid, address: result UB.
Instead of copying a pointer, copy the contents into memory.
// char* printArray[12];
#define INT_STRING_SIZE 12
char printArray[12][INT_STRING_SIZE];
...
for (int i = 0; i < 12; i++) {
snprintf(printArray[i], sizeof printArray[i], "%d", i);
}
If code must remain as char* printArray[12];, allocate memory.
for (int i = 0; i < 12; i++) {
char temp[INT_STRING_SIZE];
int len = snprintf(temp, sizeof temp, "%d", i);
printArray[i] = malloc(len + 1);
// Check for allocation omitted brevity.
memcpy(printArray[i], temp, len + 1);
// or
strcpy(printArray[i], temp);
}
And free the memory when done.

looping array of pointers to free them makes program crash in c

Full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printarray(int* array, int arraysize){
for (int i = 0; i<arraysize; i++){
printf("%d\n", *array);
array++;
}
}
void printStrArray(char** array, int arraysize){
int j = 0;
for (int i = 0; i<arraysize; i++){
j = 0;
while (array[i][j] != '\0'){
printf("%c", array[i][j]);
j++;
}
printf("\n");
}
}
int isStringInArray(char* string, char** stringArray, int arrayLen){ // returns 1 if string is contained in the array.
for (int i = 0; i < arrayLen; i++){
if (strcmp(string, stringArray[i]) == 0){
//printf("%s is equal to %s %d\n", string, stringArray[i], i);
return 1;
}
}
return 0;
}
int lenstring(char* string){ // checks string length (works only if string has null character at the end.)
char currchar = string[0];
int strlen = 0;
while (currchar != '\0'){
strlen++;
currchar = string[strlen];
}
return strlen;
}
char** riassemble(char* stringa){
char** riassembleds = calloc(1, sizeof(char*));
char* charLen = malloc(sizeof(char));
riassembleds[0] = charLen;
int riassembledLen = 1;
int stringalen = lenstring(stringa);
char tempstring[stringalen];
strcpy(tempstring, stringa);
for (int i = 0; i < stringalen; i++){
for (int j = 0; j < stringalen; j++){
tempstring[i] = stringa[j];
tempstring[j] = stringa[i];
//printf("%s\n", tempstring);
if (isStringInArray(tempstring, riassembleds, riassembledLen) == 0){
riassembleds = realloc(riassembleds, (riassembledLen+1)*sizeof(char*));
riassembledLen++;
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
printf("%p\n", riassembleds[riassembledLen-1]);
strcpy(riassembleds[riassembledLen-1], tempstring);
}
strcpy(tempstring, stringa);
}
}
*charLen = (char)riassembledLen;
riassembleds[0] = charLen; /*return the array with the length of the it casted into a char pointer as the first element*/
return riassembleds;
}
int main(int argc, char *argv[]){
char** array = riassemble("ciao");
int arraylen = (int)(*(array[0]));
printf("\n%d\n", arraylen);
printStrArray(array, arraylen);
for (int i=0; i<arraylen; i++) {
free(array[i]);
}
free(array);
return 0;
}
i'm making a function that returns an array of pointers to a char, in which the first element is a pointer that points to the length of the array casted into a char.
When i try to free the elements in the array with
char** array = riassemble("ciao"); /*Creates the array*/
int arraylen = (int)(*(array[0])); /*Gets the length*/
for (int i=0; i<arraylen; i++) {
free(array[i]);
}
The program crashes after trying to free the second element of the array which is defined here:
riassembleds = realloc(riassembleds, (riassembledLen+1)*sizeof(char*));
riassembledLen++;
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
printf("%p\n", riassembleds[riassembledLen-1]);
strcpy(riassembleds[riassembledLen-1], tempstring);
I really don't understand why this happens, one thing i noticed is that if i print the pointers that it's trying to free, they're not the same as when i print them right after allocating them in the riassemble function, but other than that i have no idea what i'm doing wrong.
edit: i was wrong about the fact that they're not the same, they actually are, i got confused.
Your function lenstring will return the length of the string without the terminating null character.
Therefore, the line
char tempstring[stringalen];
will create an array tempstringthat is sufficient in size to store the string stringa without the terminating null character.
However, the function call
strcpy(tempstring, stringa);
requires that tempstring is large enough to store stringa with the terminating null character. You are therefore writing to tempstring out of bounds, invoking undefined behavior.
In order to fix this, I recommend that you change the line
char tempstring[stringalen];
to:
char tempstring[stringalen+1];
The line
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
has the same problem, as it only allocates sufficient space without the terminating null character, which causes the line
strcpy(riassembleds[riassembledLen-1], tempstring);
to invoke undefined behavior for the same reason.
Therefore, the line
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
should be changed to
riassembleds[riassembledLen-1] = calloc(stringalen+1, sizeof(char));
I was able to find these errors very easily by using AddressSanitizer on your program.

Segmentation fault and 'free' called on a pointer to an unallocated object

I am currently writing a program to simply reverse a string in C. However, when I try to copy the contents of the temp string I made into the original string, I get a segmentation fault. Also, when I try to free the memory I allocated for my test string I get a warning which says " 'free' called on a pointer to an unallocated object "
Here is my code:
void reverseString(char* str, size_t size) {
char *temp = (char*) malloc(sizeof(str) + 1);
int j = size;
for (int i = 0; i < size; i++) {
temp[i] = str[j];
j--;
}
for (int i = 0; i < size; i++) {
str[i] = temp[i];
}
free(temp);
return;
}
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
result = "Forty-two";
reverseString(result, strlen(result));
printf("%s", result);
free(result);
result = NULL;
return 0;
}
On the second line, you should be using strlen instead of sizeof, because otherwise you will be allocating space for a character pointer and you need more than that.
sizeof(str) returns size of pointer not length of the literal.
Array index starts from 0. That's why j should starts with (size - 1)
You are allocating memory from heap, use memset before do something.
#bereal already says, if you want to understand more, please check this out :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
memset(result, 0, 10);
printf("Addr of result var : %p \n", result);
result = "Re-assign";
printf("Addr of result var : %p \n", result);
return 0;
}
Maybe my solution gives an idea for you
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverseString(char** str, size_t size) {
char *temp = (char*) malloc(size + 1);
memset(temp, 0, size + 1);
int j = size - 1;
for (int i = 0; i < size; i++) {
temp[i] = str[0][j];
j--;
}
//Change addr of holding str
*str = temp;
return;
}
int main() {
char* result = "Forty-two";
reverseString(&result, strlen(result));
printf("%s", result);
//result holds same addr with temp
free(result);
return 0;
}
But there are ways to solve this question more accurately.

How to access elements of char array passed as a parameter to a function in c?

I have this function which receives a pointer to char array and initializes it to be len repetitions of "a":
void test(char ** s, int len) {
*s = (char *)malloc(sizeof(char) * len);
int i;
for(i = 0; i < len; i++) {
*(s[i]) = 'a';
}
printf("%s\n", *s);
}
in the main() I have this code:
char * s;
test(&s, 3);
but I get EXC_BAD_ACCESS (code=1, address=0x0) error when I run main(). The error occurs on the second iteration of the for loop in this line: *(s[i]) = 'a';
As far as I understand I'm not accessing the elements correctly, what is the correct way?
s is declared as a pointer to a pointer. In reality, it's a pointer to a pointer to the start of an array, but that cannot be inferred from the type system alone. It could just as well be a pointer to a start of an array of pointers, which is how s[i] treats it. You need to first derefence s (to get the pointer to the array's start), and then index on it:
(*s)[i] = 'a';
Also, as #MFisherKDX correctly pointed out in comments, if you're going to pass *s to printf or any other standard string-manipulation function, you have to turn into a proper C string by terminating it with a 0 character.
This more clearly shows what you should be doing, while staying close to your original code:
void test(char ** s, int len) {
char *p = malloc(len);
int i;
for(i = 0; i < len; i++) {
p[i] = 'a';
}
printf("%s\n", p);
*s = p;
}
Note that sizeof(char) is always one by definition, and in C there's no need to cast the result of malloc().
That code also has all your original problems in that it doesn't actually create a string that you can send to printf( "%s... ). This fixes that problem:
void test(char ** s, int len) {
char *p = malloc(len+1);
int i;
for(i = 0; i < len; i++) {
p[i] = 'a';
}
p[i]='\0';
printf("%s\n", p);
*s = p;
}
And this is even easier, with no need to use a double-* pointer:
char *test(int len) {
char *p = malloc(len+1);
int i;
for(i = 0; i < len; i++) {
p[i] = 'a';
}
p[i]='\0';
printf("%s\n", p);
return(p);
}
Instead of assignment
*(s[i]) = 'a';
use this:
(*s)[i] = 'a';
But do not forget that C/C++ strings are null terminated
Or you can use this approach to get more readable code:
void test(char** s, int len) {
// 1 char extra for zero
char *str = (char*)malloc(sizeof(char) * (len+1));
int i;
for(i = 0; i < len; i++)
str[i] = 'a';
// zero terminated string
str[len] = 0;
printf("%s\n", str);
*s = str;
}

Difficulties with creating the Cartesian product of a pointer to char pointer

As input I have a pointer to char pointer containing:
{"ab", "cd"}
As output I need to create the following Cartesian product:
{"abab", "abcd", "cdab", "cdcd"}
I created a function that receives "ab, cd" and a pointer to char pointer that is meant to hold the resulting set. Although everything seems to be working fine inside the function, once it gets exited, my output remains empty. I suppose I'm doing something wrong during the concatenation but I'm not sure what.
This is how my code looks like:
#include <stdio.h>
void Permute(char**, int, char**);
main() {
// my input
int words = 2;
char **input;
input = malloc(sizeof(char*) * words);
input[0] = "ab";
input[1] = "cd";
// compute how much memory we need
char **output;
output = malloc(sizeof(char*) * (words * 2));
// start permutation
Permute(input, words, output);
// show output
int i = 0;
for(i = 0; i < (words * 2); ++i) {
// should print: {abcd, abab, cdab, cdcd}
// but nothing gets printed
printf("%s\n", output[i]);
}
free(input);
free(output);
}
void Permute(char **input, int words, char **output){
int i = 0, j = 0, k = 0;
char str[5];
for(i = 0; i < words; ++i) {
for(j = 0; j < words; ++j) {
strcpy (str, input[i]);
strcat (str, input[j]);
output[k] = str;
// at this point concatenation is printed correctly
printf("%s\n", output[k]); correctly
++k;
}
}
}
Edit
Thanks to Goz's comment I updated my function. Now, a pointer to char gets allocated, is pointed to the concatenation and is then stored inside output[k]. This way no data is lost when exciting the funcion:
void Permute(char **input, int words, char **output){
int i = 0, j = 0, k = 0;
char *p;
for(i = 0; i < words; ++i) {
for(j = 0; j < words; ++j) {
p = malloc(sizeof(char*) * 5);
strcpy(p, input[i]);
strcat (p, input[j]);
output[k] = p;
printf("%d %s \n", k, output[k]);
++k;
}
}
}
Edit
The buffer holding the result gets allocated before passing it over to the Permute function:
// compute how much memory we need
// allocate space for 4 pointers to char
char **output = malloc(sizeof(char*) * 4);
int i = 0;
// pre-allocate space for every pointer
for(i = 0; i < 4; i++)
output[i] = malloc( sizeof( char ) * 5 );
Edit
Free all memory pointed to by char pointer before cleaning up the pointer to char pointer:
// free memory
for(i = 0; i < 4; i++ )
free( output[i] );
free(output);
for(i = 0; i < 2; i++ )
free(input[i]);
free(input);
There are a couple of issues. Firstly you allocate a char*. You then assign it to a char** and expect it to have 2 dimensionality. It doesn't. You'd need to malloc a set of char* pointers (4 * whatever your pointer size is ... ie sizeof( char* )) then malloc 5 bytes for each of those pointers.
Furthermore in Permute you overwrite the pointer value with the pointer to str (which doesn't exist outside the function). You ought to be strcpy'ing the contents of str to output[k].
In answer to the comment: Yes that will work but it would be advisable to allocate the buffer before you go into the loop.
ie
char** ptr = malloc( sizeof( char* ) * 4 );
for( int i = 0; i++; i < 4 )
{
ptr[i] = malloc( sizeof( char ) * 4 ); // sizeof( char ) == 1 but its a good habit to get into.
}
Then as said before strcpy the temporary array into the relevant char* array.
Furthermore remember that when you free the memory you need to do the opposite of the loop above. ie dealloc the 4 individual arrays and then dealloc the array of pointers. ie:
for( int i = 0; i++; i < 4 )
{
free( ptr[i] );
}
free( ptr );
ie all 5 occasions malloc is called are met with a corresponding free. If you free the array of ptr first you cannot guarantee that the memory is valid. Therefore the 4 pointers stored in that array may no longer be valid. So free them first then the array of pointers.
char str[5]; in Permute is on the stack and lost after you exit Permute. output[k] will point to an undefined place once you exit Permute.
output = malloc(sizeof(char*) * (words * 2));
Ok, you created output[0], output[1], ... but what are their values?
output[0] is a char * ... where does it point to?
And you cannot copy the address of a local variable in Permute (str) to output. That object ceases to exist once the function returns.

Resources