Ok, here's some overview about what I'm trying to achieve. I want the user to be able to enter any amount of strings, and then I want to save those strings in a double char pointer. At the moment I haven't dealt with scaling my memory allocation for my double char pointer because I want to get it working first.
char **list = malloc(sizeof(char*)*5);
for(i = 1; i < argc; i++) {
strcpy(list[i], argv[i]);
}
I honestly thought this was going to be simple, so hopefully I'm making some stupid mistake. I keep receiving a seg fault error at the strcpy function.
What you did is only allocated memory for array of pointers to strings (which is correct), but you also need to allocate memory for each string in your array:
First (simpler) option:
char **list = malloc(sizeof(char*) * argc);
for(i = 1; i < argc; i++)
{
list[i] = strdup(argv[i]);
}
second (more complex) option:
size_t n = 0;
char **list = malloc(sizeof(char*) * argc);
for(i = 1; i < argc; i++)
{
n = strlen(argv[i]) + 1;
list[i] = malloc(n);
strcpy(list[i],argv[i]));
}
You've allocated an array of pointers to strings, but you haven't allocated any space for the strings themselves. Every time you call strcpy(), you're passing it an uninitialized destination pointer. Add a line to the beginning of your loop:
list[i] = malloc(strlen(argv[i]) + 1);
If you want it to work for any number of strings, your initial allocation has to be:
char **list = malloc(sizeof(char *) * argc);
It's not correctly malloced you only malloced the main pointer not the other ones.
Try this
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char **argv) {
char **list = malloc(sizeof(char*)*argc);
int i;
for(i = 0; i < argc-1; i++) {
list[i] = malloc(sizeof(char) * (strlen(argv[i+1]) + 1));
strcpy(list[i], argv[i+1]);
printf("%s\n", list[i]);
}
return 0;
}
EDIT I forget the v in argv
EDIT (working copy edited above) output below
./temp hello this is a list of arguments
hello
this
is
a
list
of
arguments
Related
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.
I'm from the Python/JS world, so I'm having issues wrapping my head around strings and arrays in C.
I'm attempting to create a struct -- FileInfo -- which contains a 2D array so that I can store a number of email addresses. I have a function -- createFileInfo() -- which creates the struct, manages memory for the struct and array indexes, assigns an email address to the array, and returns a pointer to the struct:
typedef struct FileInfo {
char **emailArr;
} FileInfo;
FileInfo *createFileInfo(int count) {
FileInfo *fi = malloc(sizeof(FileInfo));
char *buffer;
char *emailPrefix = "test";
char *emailDomain = "#test.com";
for (int i=0; i<count; ++i) {
fi->emailArr[i] = malloc(count * sizeof(char));
}
snprintf(buffer, sizeof(char), "%s%s", emailPrefix, emailDomain);
for (int i=0; i<count; ++i) {
for(int j=0; j<count; ++j) {
fi->emailArr[i][j] = *buffer;
}
}
return fi;
}
Then, in my main() function, I'm trying to create a pointer to the struct and print the index that contains the email address. However, I cannot get the string to print.
int main() {
int count = 1;
FileInfo *fi = createFileInfo(count);
for (int i=0; i<count; ++i) {
for(int j=0; j<count; ++j) {
fprintf(stdout, "test %s\n", fi->emailArr[i][j]);
}
}
for (int i=0; i<count; ++i) {
free(fi->emailArr[i]);
}
free(fi);
return 0;
}
What am I doing incorrectly? I'm also having quite the time with memory management; is memory allocation the issue?
In order to allocate a 2D dynamic array in C, you would need to do this instead, assuming that your 2D array is of dimensions N x M, where N is the number of emails, and M a number large enough to be able to store the email (that is something bigger than the length of the longest email to be stored, +1 for the C-string Null Terminator):
fi->emailArr = malloc( N*sizeof(char *) );
for(int i = 0 ; i < N ; i++)
fi->emailArr[i] = malloc( M*sizeof(char) );
In your attempt you missed the dynamic allocation which is just before the for loop.
You should also allocate memory for your buffer pointer. Now you do:
char *buffer;
snprintf(buffer, sizeof(char), "%s%s", emailPrefix, emailDomain);
but buffer has no memory allocated for it, so no place to store the string. You could do this instead:
size_t email_len = strlen(emailPrefix) + strlen(emailDomain);
char *buffer = malloc(email_len + 1); // +1 for the Null Terminator
snprintf(buffer, email_len, "%s%s", emailPrefix, emailDomain);
I also changed the call to populate the buffer, since the 2nd parameter of snprintf(), n, is the "Maximum number of bytes to be used in the buffer".
Putting everything together, a complete, minimal and basic example would look like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct FileInfo {
char **emailArr;
} FileInfo;
FileInfo *createFileInfo(int count) {
FileInfo *fi = malloc(sizeof(FileInfo));
char *emailPrefix = "test";
char *emailDomain = "#test.com";
size_t email_len = strlen(emailPrefix) + strlen(emailDomain);
char *buffer = malloc(email_len + 1); // +1 for the Null Terminator
snprintf(buffer, email_len + 1, "%s%s", emailPrefix, emailDomain);
fi->emailArr = malloc( count * sizeof(char *) );
for(int i = 0 ; i < count; i++)
fi->emailArr[i] = malloc( (email_len + 1) * sizeof(char) );
for(int i = 0 ; i < count; i++)
strcpy(fi->emailArr[i], buffer);
return fi;
}
int main(void) {
int count = 1;
FileInfo *fi = createFileInfo(count);
for (int i = 0; i < count; ++i) {
printf("%s\n", fi->emailArr[i]);
}
for (int i = 0; i < count; ++i) {
free(fi->emailArr[i]);
}
free(fi);
return 0;
}
Output:
test#test.com
Now of course, once you understand this piece of code, you could, if you like, think of how you would generalize this code to handle more emails than one.
emailArr is not initialized. You should initialize it first:
f->emailArr = malloc(number_of_char_arrays * sizeof(char*))
buffer is not initialized, too:
buffer = malloc(char_array_length * sizeof(char))
About snprintf's 2nd argument:
Maximum number of bytes to be used in the buffer.
The generated string has a length of at most n-1, leaving space for the additional >terminating null character.
size_t is an unsigned integral type.
It should be at least 14 if you want it to copy emailPrefix and emailDomain to buffer.
fprintf(stdout, "test %s\n", fi->emailArr[i][j]);
fi->emailArr[i][j] is a single character. You should only use the first index if you want to print it by %s.
In the createFileInfo function you're effectively creating a count*count char array, which I doubt is what you want and with count = 1 it can't contain the string "test#test". You should be allocating the size of the string you want to store, not "count" chars.
int size = 9; //this should probably be a parameter of the function
for (int i=0; i<count; ++i) {
fi->emailArr[i] = malloc(size * sizeof(char));
}
And you should allocate emailArr itself first (more on this here)
fi->emailArr = malloc(count * sizeof(char *));
You're also trying to copy the string in the wrong way; right now you're copying the pointer to buffer in each character of the string, which means each "string" is actually an array of pointers and cannot be printed as a string (I'm surprised it even compiles). It also means that if the content buffer points to changes, every element in your array will change. You need to use strncpy to do what you want.
for (int i=0; i<count; ++i) {
strncpy(fi->emailArr[i], buffer, size);
}
You also forgot to allocate memory for buffer.
I suggest you try some simpler programs involving strings to familiarize yourself with pointer logic.
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
I'm trying to use scanf to fill an array of char pointers to store the input as a string. The variable T is used to build an array of size T dynamically. Then T amount of strings are entered and displayed however when I fill in the array for example if T = 2 the first line could dog and the second line cat, it prints out "cdog" and "cat". So the first letter of the first string then the all of the 2nd string. I'm not sure where my mistake is in using char*. Any help would be appreciated.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int T;
int i;
scanf("%d",&T);
char *new_array = (char*)malloc(T * sizeof(char));
for (i = 0; i < T; ++i)
{
scanf("%s", new_array+i);
}
for (i = 0; i < T; i++)
{
printf("%s\n", new_array+i);
}
}
Always check the return value of scanf().
You are not allocating space for pointers, but for bytes, which is the main problem, you need
char **new_array = malloc(T * sizeof(char *));
/* ^ ^ */
/* allocate pointer to poitners sizeof(pointer) */
if (new_array == NULL)
handleThisErrorAndDoNotTryToWriteTo_new_array();
you will also need space for each string so
new_array[i] = malloc(1 + lengthOfTheString);
if (new_array[i] == NULL)
handleThisErrorAndDoNotTryToWriteTo_new_array_i();
right before scanf(), and instead of scanf("%s", new_array + i) do this
scanf("%s", new_array[i]);
If you enable compiler warnings, the compiler should warn you that you are passing incompatible types to printf().
It would also be good, to use a length modifier for scanf() to prevent buffer overflow, and don't forget to call free() when you no longer need the pointers.
In your code, new_array is of type char *, which is not what you want. You have to change your definition to
char *new_array[T] = malloc(T * sizeof(char*));
Then, you can use the scanf() as per your previous code.
Do this instead, together with the rest of the body:
int string_size;
//this begins just after reading T
scanf("%d", &string_size);
char **new_arrays = malloc(T * sizeof(char*));
for(i = 0; i < T; i++)
{
new_arrays[i] = malloc(string_size * sizeof(char));
}
The first malloc is to specify how many strings you want, and the second malloc is to specify how big a string can be.
Further tips:
When you're writing in C, do not cast void* produced by malloc and realloc.
You should de-allocate the memory used in the reverse way:
for (i = 0; i < T; ++i)
{
free(new_array[i]);
}
free(new_array);
Always check if the memory allocation process is (un)succesful:
char **new_arrays = malloc(T * sizeof(char*));
if(new_arrays == NULL)
exit(0) //e.g.
for(i = 0; i < T; i++)
{
new_arrays[i] = malloc(string_size * sizeof(char));
if(new_arrays[i] == NULL)
exit(0) //e.g.
}
Check if the user provides valid values through scanf.
Thanks everyone. The length of the strings in the char* array can not be greater than 1000 chars so thats hard coded. Here is the final working code...
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int T;
int i;
scanf("%d",&T);
char **new_array = malloc(T * sizeof(char*));
for (i = 0; i < T ; i++)
{
new_array[i] = malloc(1000 * sizeof(char));
scanf("%s", new_array[i]);
}
for (i = 0; i < T; i++)
printf("%s\n", new_array[i]);
}
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.