free causing different results from malloc - c

Below is a C program I have written to print different combination of characters in a string.
This is not an efficient way as this algorithm creates a lot of extra strings. However my question is NOT about how to solve this problem more efficiently.
The program works(inefficiently though) and prints the different combination of the characters of string(correctly). But when I try to free the extra strings that is getting created I run into issue. The free that is causing issue is at the end of the recur_printc function (it is commented).
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 3
void recur_printc(char *, int, char *);
int main()
{
char str[] = "abc";
char *print_arr = malloc(N * sizeof(char));
//Call recur_print
recur_printc(print_arr, 0, str);
free(print_arr);
return 0;
}
void recur_printc( char *print_arr, int index, char *remaining)
{
int i, j, rem_len, index_4_next;
//base case, only last character remaining
if(strlen(remaining) == 1)
{
print_arr[index] = remaining[0];
//Print the print_arr
for(i=0; i<N; i++)
{
printf("%c",print_arr[i]);
}
printf("\n");
return;
}
//If more than one character remaining
else
{
rem_len = strlen(remaining);
for(i=0; i<rem_len; i++)
{
//Add one character to print_arr
print_arr[index] = remaining[i];
//now create the string with remaining characters
char *remaining_for_next = malloc((rem_len-1) * sizeof(char));
index_4_next = 0;
for(j=0; j<rem_len; j++)
{
if(j != i)
{
remaining_for_next[index_4_next] = remaining[j];
index_4_next++;
}
}
//call recur_print
recur_printc(print_arr, index+1, remaining_for_next);
//Free the remainin_for_next
/*------This is causing issues----*/
//free(remaining_for_next);
remaining_for_next = NULL;
}
}
}
When I ran this program in gdb I noticed that when i=1 for the first instance of recur_print, a strange thing happens with the malloc.
When this line is executed :
char *remaining_for_next = malloc((rem_len-1) * sizeof(char));
Although rem_len-1 equals to 2, malloc allocates 3 bytes, and then the whole algorithm fails because the somewhere in the code strlen of this string is used (which will be 3 instead of 2). Not sure what is happening.(This does not happen when I comment out the free() line.)
Below is gdb output :
42 char *remaining_for_next = malloc((rem_len-1) * sizeof(char));
(gdb) print remaining_for_next
$3 = 0x0
(gdb) n
43 index_4_next = 0;
(gdb) print remaining_for_next
$4 = 0x602030 "# `"
(gdb) print rem_len-1
$5 = 2
(gdb) q
Sorry for the long post. Once again, my question is NOT about how to print the combination in a different(and better) way. My question is why the above code fails when I try to free the remaining_for_next string (maybe why malloc is getting affected).

I haven't gone through everything with a fine-toothed comb but I believe the remaining_for_next string will have no null character termination. You're using strlen() which doesn't include the null character in the string length and then copying the string as if it were an array of characters. It might be a place to begin searching. I'd imagine the first time that recur_printc is called from itself, the behaviour won't be what you want. Try manually appending a null character to remaining_for_next and see if that fixes the problem.

Every time you are creating your string, you are not appending a null terminator, which causes the error.
So change this:
for(j=0; j<rem_len; j++) {
if(j != i) {
remaining_for_next[index_4_next] = remaining[j];
index_4_next++;
}
}
to this:
for(j=0; j<rem_len; j++) {
if(j != i) {
remaining_for_next[index_4_next] = remaining[j];
index_4_next++;
}
}
remaining_for_next[index_4_next] = '\0';
Output:
gsamaras#gsamaras:~/Desktop/px$ gcc -Wall main.c
gsamaras#gsamaras:~/Desktop/px$ ./a.out
abc
acb
bac
bca
cab
cba
Tip: It's almost always a must to null terminate your strings, do not forget it!
Important edit:
As alk noticed, you need to change this:
char *remaining_for_next = malloc((rem_len - 1) * sizeof(char));
to this:
char *remaining_for_next = malloc((rem_len) * sizeof(char));
in order to make space for the null terminator.
Nice question, +1.

Related

Iteratively iterating Array of Strings (pointer value seems to get "stuck")

EDIT:
I realize that the code in my OP is long and hard to read. I've highlighted the problem with 4 lines of code.
char **t = {"Hello", "World"};
char **a = t;
++(a[0]);
printf("%c\n",**t);
I want to increment through the array of strings without losing the pointer to the first character. Therefore, I initialize a new pointer 'a' to point to the first character. After I increment the 'a' pointer, though, it seems to change what 't' points to! In the printf statement, I expect that t's pointer value remain unchanged, but it seemed to increment with 'a' and now points to the second character. Why is this happening?
SOLVED:
In the above example, a and t seem to be the same pointer so if I change one (by incrementing for example), the change is also reflected in the pther. However, if I dereference t into another variable, then I can change said variable without having that change reflected in t. In the above example, this looks like
char *a = t[0];
++a;
printf("a value: %c\n", *a);
printf("t value: %c\n", **t);
I think that I had originally been confused about dereferencing since t points to a pointer. Every response I've gotten is to use array indexing as opposed to pointers, and I can see why.
ORIGINAL POST:
Say I have:
array1 {"arp", "live", "strong"}, and
array2 {"lively", "alive", "harp", "sharp", "armstrong"}
I'm trying to find the strings in array1 that are substrings of any string in array2.
To do this, I wrote a helper function (compString) that takes in the string from array1, the entire array2, and the length of array2.
Essentially, what the function does is create local pointer values for both the string pointer and the array pointer. It then extracts the first string from array2 and begins to walk through it to find a match for the first letter of the input string. If no match is found, the function will move on to the next string, until a full match is found or until it walks through the entire array2. It then returns to its calling environment.
I ran into some unexpected behavior. When I call the function (with the same arguments), after having already called it, the array pointer seems to point to exactly where it left off in the previous call.
For example, if I call compString("arp", array2, 5) then the function will flag a match starting at the a in harp.
Then, if I call compString("live", array2, 5), the function begins at the a in harp and goes to the end of the array without flagging a match.
Finally, when I call compString("strong", array2, 5), array2 is now pointing to garbage since it has already been iterated through, and does not flag a match.
Since one of the first things the helper function does is "localize" the pointers being passed (that is, create a local pointer variable and assign to it the value of the pointer being passed to the funcion, then iterate that local variable), I would assume that subsequent calls to the function wouldn't "save" the previous value of the pointer. Any pointers?
Source attached:
#include <stdio.h>
#include <string.h>
int compString(char *, char **, int);
int main(void)
{
int sz1 = 3;
int sz2 = 5;
char *p, *p2;
char *array1[] = {"arp\0", "live\0", "strong\0"};
char *array2[] = {"lively\0", "alive\0", "harp\0", "sharp\0", "armstrong\0"};
compString("arp\0",array2,5);
compString("live\0",array2,5);
compString("strong\0",array2,5);
}
int compString(char *arr1, char **arr2, int sz2)
{
printf("\n\n\n");
printf("WORD: %s\n",arr1);
int i = 0;
char *a1 = arr1;
char **a2 = arr2;
char *p;
char *p2;
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",a2[i]);
while (i < sz2)
{
printf("%c\n",*a2[i]);
if (*a1 == *a2[i])
{
char *p = a1;
char *p2 = a2[i];
while ((*p == *p2) && (*p != '\0'))
{
++p;
++p2;
}
if (*p == '\0')
{
return 1;
}
else
{
*++(a2[i]);
if (*(a2[i]) == '\0')
{
++i;
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",a2[i]);
}
}
}
else
{
*++(a2[i]);
if (*(a2[i]) == '\0')
{
++i;
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",a2[i]);
}
}
}
return 0;
}
Your loop is causing an off-by-one error. What you want to do is looping through your array of 5 strings, so from 0 to 4. We can see that when you run all three tests because they somehow depend on the result on eachother (I didn't look into the comparing logic too much, it seems rather obfuscated).
We can replicate the behavior with just one test:
compString("test", array2, 5);
So the 5 is supposed to tell it to loop from 0 to 4. In the comparison function, you have this:
int i = 0;
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
while (i < sz2)
So far, so good. The i < sz2 is correct, it supposedly loops from 0 to 4, assuming you increase i correctly.
Then, however, you do this somewhere at the end of the function:
++i;
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
So when i is 4, you increase it to 5, and at that point the function should stop looping through the array, but at that point you do that print that tries to access a2[5], which doesn't exist. That's where it crashes for me on MSVC.
My suggestion is that you rework your loop logic to something like this:
for (int i = 0; i < sz2, i++){
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
// do something with a2[i] and don't manually change the value of "i"
}
Also, I would tidy up that string logic, there might be a bug in it somewhere. You don't need all those suspicious dereferencing calls. When you want to access character x of string y in a2, then a2[y][x] does the trick. For instance, if you want to find some letter, simply do:
for (int n = 0; n < strlen(a2[y]), n++){
if (a2[y][n] == 'a')
printf("found letter 'a' at position %d\n", n);
}
Furthermore, you don't need to add \0 to string literals. Those are automatically added, so you're just adding a second one. Instead of this:
char *array1[] = {"arp\0", "live\0", "strong\0"};
Do this:
char *array1[] = {"arp", "live", "strong"};
Also, I don't know if you have to implement this function because it's a task you've been given, but if you just want to find substrings, then you don't need to reinvent the wheel as strstr already does that.
are you looking for something like this:
char *array1[] = {"arp", "live", "strong", NULL};
char *array2[] = {"lively", "alive", "harp", "sharp", "armstrong", NULL};
void findsrings(char **neadles, char **haystack)
{
while(*neadles)
{
char **hay = haystack;
size_t pos = 0;
printf("Searching for %s\n", *neadles);
while(*hay)
{
if(strstr(*hay, *neadles))
{
printf("Found!! Haystack word is: %s at index %zu in haystack\n", *hay, pos);
}
pos++;
hay++;
}
neadles++;
}
}
int main()
{
findsrings(array1, array2);
return 0;
}
you do not need the '\0' at the end of the string literals as they are added automatically by the C compiler. I have added NULL wihch terminates the array of the string pointers - so you do not need to provide the sizes of the arrays/.
As mentioned in the comments the side effect you've noticed, is due to this line *++(a2[i]); which is altering the contents of your second array. As time progresses you'll eventually end up with the second array having no actual words in it.
Generally your code is overly complicated and you're using while loops when for loops are better suited.
The outer loop for example would work better as:
for(i=0;i<sz2;i++)
{
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",arr2[i]);
And then since you want to check each substring in arr2[i], you can use a for loop for that...
for(wordstart=arr2[i];*wordstart!='\0';wordstart2++)
{
Finally, you have an inner loop that compares each character of arr1 with the substring defined by the wordstart. You need to make sure that neither p1 or p2 goes beyond the end of their respective strings and that they point to the same character.
for(p1=arr1,p2=wordstart;(*p1!='\0')&&(*p2!='\0')&&(*p1==*p2);p1++,p2++);
Once any of those 3 conditions is no longer true, if you check that p1 has reached the end of the string, you know that it must have found a substring.
if(*p1=='\0')
{
printf("Matched %s\n",arr2[i]);
return 1;
}
The resulting function looks like:
int compString(char *arr1, char **arr2, int sz2)
{
printf("\n\n\n");
printf("WORD: %s\n",arr1);
int i = 0;
char *p1;
char *wordstart;
char *p2;
for(i=0;i<sz2;i++)
{
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",arr2[i]);
for(wordstart=arr2[i];*wordstart!='\0';wordstart++)
{
for(p1=arr1,p2=wordstart;(*p1!='\0')&&(*p2!='\0')&&(*p1==*p2);p1++,p2++);
if(*p1=='\0')
{
printf("Matched %s\n",arr2[i]);
return 1;
}
}
}
return 0;
}
Other things to note is that you don't need to implicitly add the \0 to a string. The following is just fine.
char *array1[] = {"arp", "live", "strong"};
You could also add NULL as the last element in the list of strings so that you don't need to track how many strings there are.
char *array2[] = {"lively", "alive", "harp", "sharp", "armstrong"};
which means the outer loop could be simplified to
for(i=0;arr2[i];i++)

Counting strings in C, using fgets and strstr

This is part of an assignment, so the instructions are clear and I'm not allowed to use anything other than what is specified.
The idea is simple:
1) Create an array of structs which hold a string and a count
2) Count the occurrence of the string in each struct and store the count in that struct
3) Print the strings and their number of occurrences
I have been explicitly told to use the fgets and strstr functions
Here is what I've got so far,
#define MAX_STRINGS 50
#define LINE_MAX_CHARS 1000
int main(){
int n = argc - 1;
if (n > MAX_STRINGS) {
n = MAX_STRINGS;
}
Entry entries[MAX_STRINGS];
char **strings = argv+1;
prepare_table(n, strings, entries);
count_occurrences(n, stdin, entries);
print_occurrences(n, entries);
}
void prepare_table (int n, char **strings, Entry *entries) {
// n = number of words to find
// entries = array of Entry structs
for (int i = 0; i < n; i++){
Entry newEntry;
newEntry.string = *(strings + 1);
newEntry.count = 0;
*(entries + i) = newEntry;
}
}
void print_occurrences (int n, Entry *entries) {
for (int i = 0; i < n; i++){
printf("%s: %d\n", (*(entries + i)).string, (*(entries + i)).count);
}
}
void count_occurrences (int n, FILE *file, Entry *entries) {
char *str;
while (fgets(str, LINE_MAX_CHARS, file) != NULL){
for (int i = 0; i < n; i++){ // for each word
char *found;
found = (strstr(str, (*(entries + i)).string)); // search line
if (found != NULL){ // if word found in line
str = found + 1; // move string pointer forward for next iteration
i--; // to look for same word in the rest of the line
(*(entries + i)).count = (*(entries + i)).count + 1; // increment occurrences of word
}
}
}
}
I know for a fact that my prepare_table and print_occurrences functions are working perfectly. However, the problem is with the count_occurrences function.
I've been given a test file to run which just tells me that I'm not producing the correct output. I can't actually see the output to figure out whats wrong
I'm new to pointers, so I'm expecting this to be a simple error on my part. Where is my program going wrong?
fgets(char * restrict str, int size, FILE * restrict stream) writes into the buffer at str... but you don't have a buffer at str. What is str? It's just a pointer. What's it pointing at? Garbage, because you haven't initialized it to something. So it might work or it might not (edit: by which I mean you should expect it not to work, and be surprised if it did, thank you commenters!).
You could fix that by allocating some memory first:
char *str = malloc(LINE_MAX_CHARS);
// do your stuff
free(str);
str = NULL;
Or even statically allocating:
char str[LINE_MAX_CHARS];
That's one problem I can see anyway. You say you don't have output, but surely you can add some debug statements using fprintf(stderr, "") at the very least..?

Clear char array in C without any standard library

I'm working on a class project that would require me to make unique strings and I want to concatenate a number to a string. However I do NOT have access to C Standard Library (memset, malloc, etc.). I made this which works:
char* concat(char* name, int num) {
int i, j;
char newName[50], stack[5];
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
name[0] = '\0';
return newName;
}
But then as I tested it with multiple strings, I realized that newName was being reused over and over. For ex.
This test file outputs the following:
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca); /* bill2ca1 */
Write(bill); /* bill2ca1 */
}
It successfully appends the 1 to rebecca, but then when I call concat on bill, it overwrites the first 5 letter but keeps the same chars from before in newName.
QUESTION: How to clear a char array so the next time it's called it will be set to empty, or dynamically allocate it (without using C Standard Library)?
Without using malloc, you can simply put the memory on the stack of the calling function, to keep in the scope where it is needed. It's easier to add the buffer pointer to the argument list like so:
char* concat(char *newName, char* name, int num) {
int i, j;
char stack[5];
:
:
}
int main() {
char rebecca[50];
char bill[50];
concat(rebecca, "rebecca", 1);
concat(bill, "bill", 2);
write(rebecca);
write(bill);
}
Generally speaking, assign memory where it will be used. Embedded programming (which might need to run for months without a reboot) avoids malloc like the plague, just because of the risk of memory leaks. You then need to assign extra space since you may not know the size at compile time, and then ideally check for running past the end of the buffer. Here we know the string sizes and 50 chars is more than enough.
Edit:
The other issue is that you're not null terminating. The print will go until it hits 0x00. Your line
name[0] = '\0';
should be
newName[i] = '\0';
You've got a major issue that you're overlooking. In your function, newName is a local variable (array) and you're returning it from the function. This invokes undefined behavior. The beauty of UB is that, sometime it appears to work as expected.
You need to take a pointer and allocate memory dynamically instead, if you want to return it from your concat() function. Also, in the main(), after using it, you need to free() it.
A better alternative, maybe, if you choose to do so, is
Define the array in the caller.
Pass the array to the function.
Inside the function, memset() the array before you perform any other operation.
One thing to remember, this way, every call to the function will clean the previous result.
EDIT:
If you cannot use memset(), in the main, you can use a for loop like
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
arr[i] = 0;
to clear the array before passing it on next time.
You're returning the address of a local variable. Since the variable goes out of scope when the function returns, this invokes undefined behavior.
You function should dynamically allocate memory for the result of the concatenation, then return that buffer. You'll need to be sure to free that buffer later to prevent a memory leak:
char* concat(char* name, int num) {
int i, j;
char *newName, stack[5];
// allocate enough space for the existing string and digits for a 64-bit number
newName = malloc(strlen(name) + 30);
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
newName[i] = '\0';
return newName;
}
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca);
Write(bill);
free(rebecca);
free(bill);
}

Having trouble reading strings from stdin

I need to create program that takes input from stdin in this format:
abcde //number of characters in word = number of words => square shape
fghij
klmno
pqrst
uvwxy
// \n separates first half from second
word1word //any amount of characters, any amount of words
word
word2
sdf
// \n to end input
My code works, but only about 50% of the time. I have couple of example inputs, that I use for testing, but for some of them my readwords function fails.
Here is my function, that reads words. Since I have no idea how many words or how long they are going to be, I use dynamic arrays and getchar() function.
void readWords(char **p,int *n,int w) /* before calling: n = 50; w = 20; p = 50x20 char array */
{
int i = 0,j = 0,x;
char tmp,prevtmp;
while (1)
{
prevtmp = tmp;
tmp = getchar();
if ((prevtmp == '\n' && tmp == '\n') || feof(stdin))
break; /* no more words to read */
if (tmp == '\n') /* end of word */
{
p[i][j] = '\0'; /* add \0 to create string format */
i++;
j = 0;
if (i == *n) /* if there is more words than there is space for them, double the size */
if (realloc(p,*n*2) != NULL)
*n*=2;
continue;
}
p[i][j] = tmp;
j++;
if (j == w) /* if width of word is larger than allocated space, double it */
{
for (x = 0; x < *n;x++);
if(realloc (p[x],w*2) != NULL);
w=w*2;
}
}
*n = i;
}
This is example of input for which this works (note:this function only reads second half after line with only \n):
dsjellivhsanxrr
riemjudhgdffcfz
<skipping>
atnaltapsllcelo
ryedunuhyxhedfy
atlanta
saltlakecity
<skipping 15 words>
hartford
jeffersoncity
And this is input that my function doesn't read properly:
<skipping>
...oywdz.ykasm.pkfwb.zazqy...
....ynu...ftk...zlb...akn....
missouri
delaware
<skipping>
minnesota
southdakota
What my function reads from this input:
e
yoming
xas
florida
lvania
ana
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
There is no difference between those two inputs (except different words and different amount and length of words), the first half gets read properly no matter what, but only the second half bugs out. How do I fix this?
P.S. sorry for long post, in case you want to see full input without skipped bytes, here is pastebin: http://pastebin.com/hBGn2tej
realloc() returns the address of the newly allocated memory, it does not update the argument passed into it. So this (and the other use of realloc()) is incorrect:
if (realloc(p,*n*2) != NULL)
and will results in the code accessing memory incorrectly, causing undefined behaviour. Store the result of realloc() to a temporary variable and check for non-NULL before updating p. The argument to realloc() also indicates the number of bytes, not the number of elements so the size argument calculation is incorrect as p is an array of char* so it should be realloc(p, sizeof(char*) * (*n * 2));. However, the change to p would not be visible to the caller. Also note that the only legal arguments to realloc() are pointers obtained from a previous call to malloc(), realloc() or calloc(). The comment p = 50x20 char array in the code suggests this is not the case.
Here is a small example that allocates an array of char* which should be helpful:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void f(char*** p)
{
/* Allocate space for two 'char*' elements.
Add a NULL pointer element as sentinel value
so caller knows where to find end of list. */
*p = malloc(sizeof(**p) * 3);
/* Allocate space for the two strings
and populate. */
(*p)[0] = malloc(10);
(*p)[1] = malloc(10);
strcpy((*p)[0], "hello");
strcpy((*p)[1], "world");
(*p)[2] = NULL;
/* Add a third string. */
char** tmp = realloc(*p, sizeof(**p) * 4);
if (tmp)
{
*p = tmp;
(*p)[2] = malloc(10);
strcpy((*p)[2], "again");
(*p)[3] = NULL;
}
}
int main()
{
char** word_list = 0;
f(&word_list);
if (word_list)
{
for (int i = 0; word_list[i]; i++)
{
printf("%s\n", word_list[i]);
free(word_list[i]);
}
}
free(word_list);
return 0;
}
Additionally:
prevtmp has an unknown value upon its first use.
getchar() actually returns an int and not a char.

How to overwrite an array of char pointers with a larger list of char pointers?

My function is being passed a struct containing, among other things, a NULL terminated array of pointers to words making up a command with arguments.
I'm performing a glob match on the list of arguments, to expand them into a full list of files, then I want to replace the passed argument array with the new expanded one.
The globbing is working fine, that is, g.gl_pathv is populated with the list of expected files. However, I am having trouble copying this array into the struct I was given.
#include <glob.h>
struct command {
char **argv;
// other fields...
}
void myFunction( struct command * cmd )
{
char **p = cmd->argv;
char* program = *p++; // save the program name (e.g 'ls', and increment to the first argument
glob_t g;
memset(&g, 0, sizeof(g));
g.gl_offs = 1;
int res = glob(*p++, GLOB_DOOFFS, NULL, &g);
glob_handle_res(res);
while (*p)
{
res = glob(*p, GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
glob_handle_res(res);
}
if( g.gl_pathc <= 0 )
{
globfree(&g);
}
cmd->argv = malloc((g.gl_pathc + g.gl_offs) * sizeof *cmd->argv);
if (cmd->argv == NULL) { sys_fatal_error("pattern_expand: malloc failed\n");}
// copy over the arguments
size_t i = g.gl_offs;
for (; i < g.gl_pathc + g.gl_offs; ++i)
cmd->argv[i] = strdup(g.gl_pathv[i]);
// insert the original program name
cmd->argv[0] = strdup(program);
** cmd->argv[g.gl_pathc + g.gl_offs] = 0; **
globfree(&g);
}
void
command_free(struct esh_command * cmd)
{
char ** p = cmd->argv;
while (*p) {
free(*p++); // Segfaults here, was it already freed?
}
free(cmd->argv);
free(cmd);
}
Edit 1: Also, I realized I need to stick program back in there as cmd->argv[0]
Edit 2: Added call to calloc
Edit 3: Edit mem management with tips from Alok
Edit 4: More tips from alok
Edit 5: Almost working.. the app segfaults when freeing the command struct
Finally: Seems like I was missing the terminating NULL, so adding the line:
cmd->argv[g.gl_pathc + g.gl_offs] = 0;
seemed to make it work.
argv is an array of pointers of char *. This means that argv has space for argc char * values. If you try to copy more than that many char * values into it, you will end up with an overflow.
Most likely your glob call results in more than argc elements in gl_pathv field (i.e, gl_pathc > argc). This is undefined behavior.
It is similar to the code below:
/* Wrong code */
#include <string.h>
int a[] = { 1, 2, 3 };
int b[] = { 1, 2, 3, 4 };
memcpy(a, b, sizeof b);
Solution: you should either work with the glob_t struct directly, or allocate new space to copy gl_pathv to a new char **:
char **paths = malloc(g.gl_pathc * sizeof *paths);
if (paths == NULL) { /* handle error */ }
for (size_t i=0; i < g.gl_pathc; ++i) {
/* The following just copies the pointer */
paths[i] = g.gl_pathv[i];
/* If you actually want to copy the string, then
you need to malloc again here.
Something like:
paths[i] = malloc(strlen(g.gl_pathv[i] + 1));
followed by strcpy.
*/
}
/* free all the allocated data when done */
Edit: after your edit:
cmd->argv = calloc(g.gl_pathc, sizeof(char *) *g.gl_pathc);
it should work, but each of argv[1] to argv[g.gl_pathc + g.gl_offs - 1] is a char * that is "owned" by the struct glob. Your memcpy call is only copying the pointers. When you later do globfree(), those pointers don't mean anything anymore. So, you need to do copy the strings for your use:
size_t i;
cmd->argv = malloc((g.gl_pathc+g.gl_offs) * sizeof *cmd->argv);
for (i=g.gl_offs; i < g.gl_pathc + g.gl_offs; ++i)
cmd->argv[i] = strdup(g.gl_pathv[i]);
This makes sure you now have your own private copies of the strings. Be sure to free them (and argv) once you are done.
There are a few other problems with your code.
You are doing *p++, you should do p++, since you're not using the value of the dereferencing.
You should really check the return value of glob.
Your paths variable needs g.gl_pathc + 1 elements, not g.gl_pathc. (Or more correctly, you need to allocate g.gl_pathc + g.gl_offs times sizeof *paths bytes.)
Your for loop to copy strings should be for (j=1; j < g.gl_pathc + g.gl_offs; ++j).
Make sure you prevent shell from expanding your glob. I.e., call ./a.out '*' instead of ./a.out *.
Don't you need to multiple g.gl_pathc by sizeof(char *)?

Resources