How can I change an array of string pointers in another function? - c

I have been trying to figure out how to modify an array of char pointers but no matter what I do there appears to be no change below are the three arrays I'm trying to change including the call to the function I'm using.
char*cm1[5];
char*cm2[5];
char*cm3[5];
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
The code below is the function itself.I was thinking that maybe it involves a double pointer but if I try *cmd to change the array I get a segmentation fault.
void setupCommands(char **cmd[], char* commands[],char file[],int index){
char str1[255];
strcpy(str1,commands[index]);
char newString [5][255];
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=str1[i];
j++;
}
}
for(i = 0; i < ctr; i++){
//printf(" test2 %s \n", newString[i]);
cmd[i] = newString[i];
//printf(" test2 %d %s \n", i,cmd[i]);
}
//printf("index %d", i);
cmd[i]= file;
cmd[i + 1] = NULL;
//execvp(cmd[0],cmd);
//cmd
}

There are a few issues with your code:
you are trying to return references to the local 'char newString [5][255]' when the function exits. In simple worlds - never return anything locally allocated on the stack. This is the reason you are getting the segmentation fault.
char **cmd[] must be declared char *cmd[] - even though you will get a warning from the compiler assignment from incompatible pointer type, the code would run and execute correctly(essentially **cmd[] would do the same work as *cmd[], even though it's not of correct type) if you didn't return references to the local object;
Easy and simple optimization is just to remove the array str1 and directly operate on the array commands.
Apart from this simple optimization I have changed your code to overcome the segmentation fault, by allocating on the heap, instead on stack(will live until the program terminates) the multidimensional array, and I also calculate it's size so I will know how much memory to allocate. Now it's safe to return references to it.
Note that more optimizations could be made, but for the sake of the simplicity this is the bare minimal for this code to work.
int setupCommands(char *cmd[], char *commands[], char file[], int index)
{
int j = 0;
int ctr = 0;
int i = 0;
int rows = 0;
int cols = 0;
char **newString = NULL;
while(commands[index][i])
{
if (commands[index][i] == ' ')
{
++rows;
}
++i;
}
++rows;
cols = strlen(commands[index]) + 1;
newString = malloc(rows * sizeof(*newString));
if (newString == NULL)
{
return -1;
}
for (i = 0; i < rows; ++i)
{
newString[i] = malloc(cols * sizeof(*newString));
if (newString[i] == NULL)
{
return -1;
}
}
for(i = 0; i <= strlen(commands[index]); i++){
if(commands[index][i] == ' '|| commands[index][i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=commands[index][i];
j++;
}
}
for(i = 0; i < ctr; i++){
cmd[i] = newString[i];
}
cmd[i]= file;
cmd[i + 1] = NULL;
return 0;
}

First of all - being the three stars pointer programmer is not good :)
You assign it with pointer to the local variable which is not longer available after the function return
But if you still want the three stars pointers:
char **cm1;
char **cm2;
char **cm3;
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
#define MAXWORD 256
int setupCommands(char ***cmd, const char *commands,const char *file,int index){
char str1[255];
strcpy(str1,commands[index]);
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
*cmd = malloc(sizeof(char *));
**cmd = malloc(MAXWORD);
if(!*cmd || !**cmd)
{
/* do spmething if mallocs failed*/
return -1;
}
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
(*cmd)[ctr][j] = '\0';
ctr++;//next row
*cmd = realloc((ctr + 1) * sizeof(int));
(*cmd)[ctr] = malloc(MAXWORD);
if(!*cmd || !*cmd[ctr])
{
/* do spmething if mallocs failed*/
return -1;
}
j=0;// for next word, init index to 0
}else{
(*cmd)[ctr][j]=str1[i];
j++;
}
}
*cmd = realloc(sizeof(char *) * ctr + 2)
(*cmd)[ctr - 2] = malloc(MAX);
if(!*cmd || !*cmd[ctr - 2])
{
/* do spmething if mallocs failed*/
return -1;
}
strcpy((*cmd)[ctr - 2], file);
(*cmd)[ctr - 1] = NULL;
return 0;
//execvp(cmd[0],cmd);
//cmd
}
you can improve many things (for example do not realloc every time but in the larger chunks) and I did not change anything in your code logic.

Related

Selection of unique characters

Please, help with the code.
Requirement:
Write a function my_union that takes two strings and returns, without doubles, the characters that appear in either one of the strings.
Example:
Input: "zpadinton" && "paqefwtdjetyiytjneytjoeyjnejeyj"
Output: "zpadintoqefwjy"
My code:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
char *my_union(char *a, char *b) {
char *str;
// Algorithm for excluding nonunique characters from string a(given in
// parameters).
str[0] = a[0];
int k = 1;
str[k] = '\0';
for (int i = 1; a[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == a[i]) {
is = false;
break;
}
}
if (is) {
str[k] = a[i];
k++;
str[k] = '\0';
}
} // In this case we are excluding excess character 'n' from "zpadinton", so
// str is equal to "zpadinto".
// Algorithm for adding unique characters from array b(given in parameters)
// into str.
for (int i = 0; b[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == b[i]) {
is = false;
break;
}
}
if (is) {
strncat(str, &b[i], 1);
}
}
return str;
}
The first algorithm is almost identical with second, but it doesn't work(. Mb I messed up with memory, give some advice, pls.
If you mean, get the unique characters from two strings and store them into a new string, try this code ;
First, you must allocate a memory for str. In your code, str is not pointing allocated memory location, so you will probably get segmentation fault.
int contains(const char * str,char c)
{
for (int i = 0; i < strlen(str); ++i)
if(str[i] == c)
return 1;
return 0;
}
char * my_union(char *a, char*b)
{
char * res = (char*)malloc(sizeof(char)*(strlen(a) + strlen(b)));
int pushed = 0;
for (int i = 0; i < strlen(a); ++i)
{
if(!contains(res,a[i])){
res[pushed] = a[i];
pushed++;
}
}
for (int i = 0; i < strlen(b); ++i)
{
if(!contains(res,b[i])){
res[pushed] = b[i];
pushed++;
}
}
return res;
}
int main(int argc, char const *argv[])
{
char string1[9] = "abcdefgh";
char string2[9] = "abegzygj";
char * result = my_union(string1,string2);
printf("%s\n", result);
return 0;
}
Also, do not forget the free the return value of my_union after you done with it.

Segmentation fault in C with dynamic array

Please help me find an error in dynamic memory allocation.
It is necessary to print all the words that begin and end with one letter.
The algorithm works with a static array, but there is an error when trying to create a dynamic array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int len = 0;
char str[10] = "aba cd geg ";
char* word = NULL;
int j = 0;
int i = 0;
int n = 0;
while(str[i]!='\0')
{
if(!isspace(str[i]))
{
n++;
word = (char*)realloc(word, (n* sizeof(char)));
word[j] = str[i];
j++;
len++;
}
else
{
if(word[0] == word[len-1])
{
j = 0;
while(j < len)
{
printf("%c", word[j]);
j++;
}
}
j = 0;
len = 0;
free(word);
n = 0;
}
i++;
}
return 0;
}
Once you have freed word, you need to set word to NULL, because realloc can only be performed on a NULL pointer or on a valid pointer that has previously been returned by malloc, calloc or realloc.
...
len = 0;
free(word); // after this line, word is no more a valid pointer
word = NULL; // <<<< insert this
n = 0;
...
In other words this pattern is always wrong:
free(foobar);
foobar = realloc(foobar, ...);
Another possibility is not to free word at all and let the next realloc take care of it, which in this case is most likely more efficient.
...
len = 0;
// free(word); remove this line
n = 0;
...
but then you need to call free(word); at the end of the program, just before return 0;
So the end of your program would look like this:
...
j = 0;
len = 0;
n = 0;
}
i++;
}
free(word);
return 0;

Error freeing memory after sorting the array pointer

How will I be able to maintain the position of the allocated memory so that freeing memory of a sorted array will not be affected?
I am trying to sort the pointer array. I noticed that when I free the words double pointer variable it will give an error HEAP CORRUPTION DETECTED. The input I entered was "f ff 1".
Unsorted: f ff 1
Sorted: 1 f ff
I noticed that when I sort and free it will expect the same order which is "f ff 1". That is why I got some error.
Any suggestion on how will be able to free the sorted pointer array?
#include <stdio.h>
/*
A logical type
*/
typedef enum {
false,
true,
} bool;
/*
Bubble Sort
*/
void sort(char *myargv[], int n)
{
int i, j, cmp;
char tmp[256];
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++)
{
for (j = 0; j < n-1; j++)
{
cmp = strcmp(myargv[j], myargv[j+1]);
if (cmp > 0)
{
strcpy(tmp, myargv[j+1]);
strcpy(myargv[j+1], myargv[j]);
strcpy(myargv[j], tmp);
}
}
}
}
void printArray(char *myargv[], int myargc)
{
int i = 0;
for (i = 0; i < myargc; ++i) {
printf("myargc[%d]: %s\n",i , myargv[i]);
}
}
int main (int argc, char *argv[])
{
char text[256];
char *myargv[256];
char *myargvTemp[256];
int myargc;
int i = 0;
int text_len;
bool new_word = false;
int index_start_word = 0;
char **words; //this will store the found word
int count = 0;
while(1){
printf( "Enter text:\n");
gets(text); //get the input
text_len = strlen(text); //get the length of the text
words = (char **) malloc(text_len * sizeof(char));
if (strlen(text) == 0 || text == '\0') exit(0); //exit if text is empty
for (i = 0; i < text_len ; ++i){
if(text[i] != ' '){ //if not space
if(new_word == false){
new_word = true;
index_start_word = i;
}
} else {
if (new_word == true) {
words[count] = (char *)malloc(i - index_start_word * sizeof(char)+1); //memory allocation
strncpy(words[count], text + index_start_word, i - index_start_word);
words[count][i - index_start_word] = '\0'; //place NULL after the word so no garbage
myargv[count] = words[count];
new_word = false;
count++;
}
}
if (new_word == true && i == text_len-1){
words[count] = (char *)malloc(i - index_start_word * sizeof(char)+2);
strncpy(words[count], text + index_start_word, (i+1) - index_start_word);
words[count][(i+1) - index_start_word] = '\0';
myargv[count] = words[count];
new_word = false;
count++;
}
}
myargc = count;
//not sorted
printf("myargc is: %d\n", myargc);
printArray(myargv, myargc);
//sorting happen
sort(&myargv, myargc);
printf("-----sorted-----\n");
printf("myargc is: %d\n", myargc);
printArray(myargv, myargc);
memset(myargv, 0, 255);
count = 0;
i = 0;
//free the memory of words
for (i=0; i<myargc; ++i) {
free(words[i]);
}
}
return 0;
}
There are at least 2 problems in your code:
you do not allocate enough space for the array of pointers: change the words = (char **) malloc(text_len * sizeof(char)); to this:
words = malloc(text_len * sizeof(char *));
This allocation is actually incorrect: you should compute the number of words and allocate the correct size for the pointer array, or use a fixed size array.
you swap the contents of the strings instead of swapping the pointers. This is incorrect as the various strings do not have the same lengths.
Here is a corrected version of the sorting function:
void sort(char *myargv[], int n) {
int i, j, cmp;
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++) {
for (j = 0; j < n-1; j++) {
cmp = strcmp(myargv[j], myargv[j+1]);
if (cmp > 0) {
char *tmp = myargv[j+1];
myargv[j+1] = myargv[j];
myargv[j] = tmp;
}
}
}
}
You want words to hold pointers to char so you need to change
words = (char **) malloc(text_len * sizeof(char)); //will allocate array of single byte
to
words = (char **) malloc(text_len * sizeof(char *));// will allocate array of pointers

Segmentation fault - split string

Can you please help me with fixing below code. Not sure where the segmentation fault is.
char str[] = "00ab00,00cd00";
char **strptr;
int i;
strptr = malloc(sizeof(char*) * 2);
strcnt = 0;
int j=0;
for(i=0;i<sizeof(str);i++) {
char c = *(str+i);
printf("%c", c);
if(c==',') {
strcnt++;
j=0;
}
strptr[strcnt][j++] = c;
}
Please ignore my poor coding :)
PS: I know its possible to split using strtok() easily.
Not sure where the segmentation fault is
As others have mentioned in the comments, you are not assigning memory to the pointers strptr[0] and strptr[1] but, you are trying to access them. This leads to segmentation fault.
Use a for loop to initially assign memory to strptr[0] and strptr[1]
strptr = malloc(sizeof(char*) * 2);
for(i = 0; i < 2; i++) //here, initialise each to 1 byte
{
strptr[i] = malloc(1);
}
strcnt = 0;
Here's a question on how to initialise a pointer to a pointer.
then, resize them at each step as you add additional character using the realloc() function.
for(i = 0, j = 0; i < sizeof(str); i++)
{
strptr[strcnt] = realloc(strptr[strcnt], j + 2);
//here, you resize each time to provide space for additional character using realloc()
char c = *(str + i);
printf("%c", c);
if(c == ',')
{
++strcnt;
j=0;
continue; //use a continue here
}
strptr[strcnt][j] = c;
strptr[strcnt][++j] = '\0';
//to provide null terminating character at the end of string (updated to next position at every iteration)
}
don't forget to free() the allocated memory
for( i=0; i<2; i++)
{
printf("%s\n", strptr[i]); //just to display the string before `free`ing
free(strptr[i]);
}
free(strptr);
Altogether your code would be something like this:
char str[] = "00ab00,00cd00";
char **strptr;
int i, j;
int strcnt;
strptr = malloc(sizeof(char*) * 2);
for(i = 0; i < 2; i++)
{
strptr[i] = malloc(1);
}
strcnt = 0;
for(i = 0, j = 0; i < sizeof(str); i++)
{
strptr[strcnt] = realloc(strptr[strcnt], j + 2);
char c = *(str + i);
printf("%c", c);
if(c == ',')
{
++strcnt;
j=0;
continue;
}
strptr[strcnt][j] = c;
strptr[strcnt][++j] = '\0';
}
for( i=0; i<2; i++)
{
printf("%s\n", strptr[i]);
free(strptr[i]);
}
free(strptr);
return 0;

Issue converting vector to string in c

I am trying to convert a vector into a string using the following function.
char* my_vect2str(char** input)
{
int i;
char* ret = (char*)xmalloc(sizeof(char*));
for(i=0; input[i] != NULL; i++)
{
if(*input[i] == '\0')
ret[i] = ' ';
else
ret[i] = *input[i];
}
ret[i] = '\0';
return ret;
}
This appears to be getting just the first character of each string in the vector. How do I alter my for loop to get this working properly? Thanks!
Your malloc should be the size of the pointer contents, not the pointer itself. You also don't need to cast the malloc void *. You need an inner loop counter in order to iterate through both dimensions of you pointer. This should work:
char* my_vect2str(char** input)
{
int i;
int count = 0;
char* ret = (char*)malloc(sizeof(char*)); // should be a larger size
for(i=0; input[i] != NULL; i++)
{
int j = 0;
while(1){
if(input[i][j] == '\0'){
ret[count++] = ' ';
break;
}else{
ret[count++] = input[i][j];
}
j++;
}
}
ret[count] = '\0';
return ret;
}
The first loop calculates the total size of the strings in input. Then, the space is allocated and the strings are concatenated to ret.
char* my_vect2str(char** input)
{
int i, j, k = 0;
char* ret;
int size = 0;
int len;
char* inp = input[k++];
while (inp != NULL) {
size += strlen(inp);
inp = input[k++];
}
ret = malloc((size * sizeof(char)) + 1);
memset(ret, 0, size + 1);
i = 0;
j = 0;
while (i < size) {
if (input[j] != NULL) {
len = strlen(input[j]);
memcpy(&ret[i], input[j], len);
i += len;
}
++j;
}
return ret;
}

Resources