C program pointers crashing system calls - c

// Struct for Country Data
typedef struct
{
char name[50]; // Country name
char code[3]; // Country code
int population; // Country Population
double lifeExp; // Country Life expectancy
} CountryData;
// Struct for Dir File
typedef struct
{
char code[3];
int offSet;
} DirData;
// Function Declarations
void fillCountryStructs(CountryData ** dataPtr, int nLines, int fd);
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines,int fd2);
void sortStructs(DirData **director, int nLines);
int verifyString(char *s1, char *s2);
// Main Function
// - This function starts the program, get the number of lines as a
// parameter, fills the structs and writes the data to the Country
// File and the Directory file.
int main(int argc, char *argv[]) // Always remember to pass an argument while executing
{
// Some variables
int nLines; // The number of lines
char *pEnd; // For String functions
FILE *Fin,*Fout; // File pointers
int fd;
int fd2;
nLines = strtod(argv[1], &pEnd);
CountryData **countryDataPtr; // Array of structs
CountryData **tempStruct;
DirData **director;
// Allocate memory for the struct pointers
countryDataPtr = calloc(nLines, sizeof(CountryData*));
director = calloc(nLines, sizeof(DirData*));
// File Stream for "AllCountries.dat"
if((fd = open("AllCountries.dat", O_RDWR)) ==-1)
err_sys("File not found...\n");
// File Stream for "RandomStruct.bin"
if ((fd2 = open("RandomStruct.bin", O_RDWR)) == -1)
err_sys("Failed to open binary\n");
// Filling the Country stucts
fillCountryStructs(countryDataPtr, nLines, fd);
close (fd);
//fclose(Fin); // Closing the file "AllCountries.dat"
// Writing Binary File
write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
close (fd2);
//fclose(Fout);
printf("RandomStruct.bin written Sucessfully\n");
// Filling the Directory File
// File Stream for "RandomStructDir.dir"
if ((fd2 = open("RandomStructDir.dir",O_RDWR|O_TRUNC)) != -1)
err_sys("Failed to open binary\n");
fillDirectoryStructs(countryDataPtr, director, nLines, fd2);
sortStructs(director, nLines); // Sorting the structs
// Write the number of lines in the FIRST LINE
// of the Directory File
write(fd2, nLines, sizeof(nLines));
// Writing Directory File after the number of lines was written
write(fd2,(director[0]->code[0]), sizeof(DirData));
close (fd2);
//fclose(Fout);
printf("RandomStructDir.dir written Sucessfully\n\n");
exit(0);
}
// Filling the Country structs
// - This function extracts the data from the file using strtok
// and fills all the structs with their corresponding values.
void fillCountryStructs(CountryData **dataPtr, int nLines, int fd)
{
int curLine = 0; // Current line
int index = 0; // The index
char buf[BUFSIZE]; // The Buffer with the size of BUFSIZE
char *tok; // Token
char *pEnd; // For the String functions
char ch = 'a'; // The temp character
int temPop;
double temLifeExp;
int num=0;
for(curLine = 0; curLine < nLines; curLine++)
{
// Reading each line
dataPtr[curLine] = (CountryData *)calloc(1, sizeof(CountryData));
index = 0;
do
{
read(fd, &ch, 1);
buf[index++] = ch;
}
while(ch != '\n');
// Strtoking...
tok = strtok(buf, ",\n");
index = 1;
while(tok != NULL)
{
tok = strtok(NULL, ",\n");
// Get the Country Code
if(index == 1)
{
strcpy(dataPtr[curLine]->code, tok); // Copying code to the struct
}
// Get the Country Name
if(index == 2)
{
strcpy(dataPtr[curLine]->name, tok); // Copying name to the struct
}
// Get the Country Population
if(index == 7)
{
temPop = (int)strtol(tok, &pEnd, 10);
dataPtr[curLine]->population = temPop; // Copying population to the struct
}
// Get the Country Life expectancy
if(index == 8)
{
num=countchar(tok);
printf ("The number of characters entered is %d\n", num);
printf ("The character entered is %s\n",tok);
temLifeExp = strtod(tok, &pEnd);
dataPtr[curLine]->lifeExp = temLifeExp; // Copying life expectancy to the struct
}
index++;
}
}
}
int countchar (char list[])
{
int i, count = 0;
for (i = 0; list[i] != '\0'; i++)
count++;
return (count);
}
// Filling the Directory Structs
// - This function fills the directory with the offset
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines, int fd2)
{
int i = 0;
for(i = 0; i < nLines; i++)
{
strcpy(director[i]->code, dataPtr[i]->code); //It crashes in this Line
director[i]->offSet = sizeof(CountryData) * (i);
}
}
// Sorting the Dir Structs
// - This function sorts the Directory Structs.
void sortStructs(DirData **director, int nLines)
{
int maxNumber;
int i;
DirData **temp;
temp = calloc(1, sizeof(DirData));
// Sorting the array of pointers!
for(maxNumber = nLines - 1; maxNumber > 0; maxNumber--)
{
for(i = 0; i < maxNumber; i++)
{
if((verifyString(director[i]->code, director[i+1]->code)) == 1)
{
temp[0] = director[i];
director[i] = director[i+1];
director[i+1] = temp[0];
}
}
}
}
// Veryfying the strings
// - This function compares two strings and return a specific value
// accordingly.
int verifyString(char *s1, char *s2)
{
int i;
if(strcmp(s1,s2) == 0)
return(0); // They are equal
for(i = 0; s1[i] != 0; i++)
{
if(s1[i] > s2[i])
return(1); // s1 is greater
else if(s1[i] < s2[i])
return(2); // s2 is greater
}
return (2); // s2 is greater
}
So I get segmentation fault and I have no Idea why? maybe is something about the pointers. I specified where it crashes (void fillDirectoryStructs) that method the first line.
When I compile I get :
Countries.c: In function 'main':
Countries.c:68: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:84: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:86: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:232:2: warning: no newline at end of file
I don't know a lot about pointers but I have to use system calls, so I can't use any of the FILE * functions (fwrite(), etc) that is why I'm using plain write() and read().
When I run it I get segmentation fault when It gets to that point I just specified.
for test purposes I'm trying to print this
printf("test: %s\n", countryDataPtr[0]->code[0]);
instead of writing and it crashes there, why? what am I doing wrong? shouldn't that get the code of that first country in my struct? thanks

Well, you need to listen to your compiler and take its warnings seriously.
This:
write(fd2, nLines, sizeof(nLines));
is wrong, and would explain the warning. The variable nLines has type int, but if you look at the [documentation for write()] you can see that the 2nd argument has type void *.
So it will interpret your integer value as a pointer, and start reading memory which you have no right to be reading.
You need:
write(fd2, &nLines, sizeof nLines);
Note that sizeof is not a function, it only needs parenthesis when the argument is a type name (since it then needs a cast expression to the type in question, and casts are writen as a type name enclosed in parenthesis).
Also, you need to be prepared for the reality that I/O can fail. The write() function has a return value which you should be checking.

There are a number of other problems with your code, in addition to the serious one unwind pointed out.
This:
CountryData **countryDataPtr; // Array of structs
is not an Array of structs. Once allocated, it could be an array of pointers to structs.
This:
write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
does not write one CountryData instance (much less a whole array of them). It takes the integer value of the first character of the first element's name, and treats it as a pointer just like you do with nLines.
If you want to write the first element, it would look like this:
write(fd2, countryDataPtr[0], sizeof(CountryData));
and if you wanted to write all the elements, you'd either need a loop, or a contiguous array of structs you can write in one go.

Related

I lose the values in a struct (c)

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define stock_dir "/Users/myname/prices/"
#define file_list "/Users/myname/trade/trade/nasdaq100_stock_list.txt"
#define look_back_period 3
#define num_stocks 103
#define days_of_data 21
int main()
{
FILE *stocks, *stk;
char stock[11], fullpath[50] = "\0", header[25];
char line_of_data[40];
char *sclose, *svol;
int n = 0, i = 0;
typedef struct daily_data {
char *date;
float close;
int vol;
}data;
sclose = (char*) malloc(20*sizeof(char));
svol = (char*) malloc(20*sizeof(char));
data** day_data = (data**) malloc(num_stocks*sizeof(data*) );
if (day_data == NULL)
{
printf("day_data not allocated\n");
exit(0);
}
for(i = 0; i < num_stocks; i++)
if ((day_data[i] = (data*)malloc(days_of_data*sizeof(data))) == NULL)
{
printf("data[%d] not allocated\n", i);
exit(0);
}
for(i = 0; i < num_stocks; i++)
for(n = 0; n < days_of_data; n++)
if ((day_data[i][n].date = (char*)malloc(20)) == NULL)
{ printf("data[%d][%d] not allocated\n", i,n);
exit(0);
}
/* ... code omitted ... */
if ( (stocks = fopen(file_list, "r") )== NULL)
printf("didn't open file list\n");
i = 0;
while (fgets(stock, sizeof(stock), stocks) != NULL)
{
printf("%s",stock);
strcpy(fullpath,stock_dir);
strcat(fullpath,stock);
fullpath[strcspn(fullpath, "\n")] = 0;
if ( (stk = fopen(fullpath, "r") )== NULL)
printf("didn't open quote list\n");
fgets(header,sizeof(header),stk);
n=0;
while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL)
{
fgets(line_of_data,sizeof(line_of_data),stk);
day_data[i][n].date = strtok(line_of_data, ",");
sclose = strtok(NULL,",");
day_data[i][n].close = atof(sclose);
svol = strtok(NULL, ",");
day_data[i][n].vol = atoi(svol);;
printf("%s %f %d\n",day_data[i][n].date,day_data[i][n].close,day_data[i][n].vol);
n++;
}
fclose(stk);
i++;
}
for (n = look_back_period - 1; n < (days_of_data - look_back_period); n++)
printf("%d %s %f %d\n",n, day_data[1][n].date, day_data[1][n].close, day_data[1][n].vol);
}
The print statement in the while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL) loop shows that everything went into the right place. But when I print values outside they're mostly wrong. I'm supposed to add more details but I don't know what else to say. I lose the values in the struct when I leave the loop.
You overwrite the same data again and again.
Take a look at your structure:
typedef struct daily_data {
char *date; ///< a pointer without own storage
float close;
int vol;
}data;
while processing your file you read each line into line_of_data
while(fgets(line_of_data, sizeof(line_of_data),stk) !=NULL)
you tokenize the line_data and assign the pointer to data->date
day_data[i][n].date = strtok(line_of_data, ",");
What tokenize (strtok reference) does is inserting terminators into your input string and returning the pointer to the start of the new part of your input. So no new memory is allocated at this point. the returned pointer points into your input string.
So effectively you assigning the local variable pointer to your data storage structure.
Additionally to this you lose the pointer to your initially allocated memory for the date pointer.
I would suggest you to remove the a priory allocation of date and allocate the required memory at the point you really know the required length or if you are sure, you know the maximum length, then you can just make the date member an array.
So you either have to allocate new memory and copy the tokenized data or if you made date a fixed size array, just copy the tokenized data.
on the first variant it would look like this
char * tok = strtok(line_of_data, ",");
day_data[i][n].date = malloc(strlen(tok)+1);
strcpy(day_data[i][n].date, tok);
(+ remove the pre allocation of the date member)
or the second variant:
change data to
typedef struct daily_data {
char date[20];
float close;
int vol;
}data;
and the processing code looks like this:
char * tok = strtok(line_of_data, ",");
strcpy(day_data[i][n].date, tok);
(+ (of course) remove the pre allocation of the date member)
You also should in any case add error handling if the tokenized string exceeds the max length or the format of the lines does not match the expectation (missing delimiters, wrong/invalid number(formats), ...).

Warning: cast to pointer from integer of different size (char* = function())

I am trying to find a way to store the return value of this function...
int createDirectory() {
int buffer = 21; //variable holds buffer count
int pid = getpid(); //variable calls builtin C function to get process id
char* directory = malloc(buffer * sizeof(char)); //dynamically creates array of chars
char* prefix = "schmcory.rooms." ; //prefix is set to my user id and rooms
//counts characters and stores in buffer
snprintf(directory, buffer, "%s%d", prefix, pid);
//printf("%s\n", directory); //for testing purposes
struct stat st = {0}; //initialize system struct
//if statement checks if directory exists
if(stat(directory, &st) == -1) {
mkdir(directory, 0755); //creates directory
}
free(directory); //free dynamically allocated memory
return *directory;
}
...into this variable char* directory = createDirectory();
I am getting the below error:
cast to pointer from integer of different size
I have tried the following:
char* directory = (void*)createDirectory();
char* directory = (int)createDirectory();
char directory = createDirectory(); //compiles w/o warning but prints nothing
I am trying to print the results in my main function.
printf(directory);
2 issue with the code :
return value of the function is char * not int - char * createDirectory();
you do free before you return the pointer
here is the code working (Linux environment)
//free(directory);
return directory;
}
int main( int argc, const char* argv[] )
{
char* directory = createDirectory();
printf ("main says %s \n", directory);
free(directory);
}
If I understand correctly, you want to return the result of mkdir, not the string containing the path, switch to
int ret = -1;
if (stat(directory, &st) != -1) // Notice `!=` instead of `==`
{
ret = mkdir(directory, 0755);
if (ret == -1)
{
perror("mkdir")
}
}
free(directory);
return ret;
and the caller should do something like:
int dir;
if ((dir = createDirectory()) != -1)
{
... do your stuff with dir
}
else
{
... raise exception
}
EDIT:
It seems that you want to return something like: schmcory.rooms.49111
In this case, the prototype should be
char *createDirectory(void) { // Return a pointer to `char`
instead of
int createDirectory() {
But do not call free or you end up deleting the result:
free(directory); // Remove this line
and
return *directory;
should be
return directory; // Do not dereference, you don't want the first char, you want the whole string

trying to create an array of struct pointer but get heap/buffer/etc violation statistically

i have two structs
typedef enum { False = 0, True = 1 } bool;
//defenition of candy structure
typedef struct _Candy {
char candy_name[16];
bool vegan;
}Candy;
typedef struct _Child {
char child_name[16];
Candy *candy_of_child;
}Child;
now im trying to create an array of pointers that each one is Child type
[*Child,*Child...] etc
now i can initialize it i need to do it dynamically
the function that does in is:
int AllocateKidsArray(int NumOfKids, Child** ptr_to_child_arr) {
//=================================================
//"AllocateKidsArray" intializing an array of childrens
//Input: 1. int indicating the number of kids
// 2. pointer to an array of children
//Output: 1. return an int value {0}->Success {-1}->Failure
// 2. pointer to an empty initialized array of childerns
//=================================================
// array of length NumOfKids, consisting of Child pointers
Child **ptr_to_childs = malloc(NumOfKids * sizeof(Child*));
int i;
for (i = 0; i < NumOfKids; i++) {
ptr_to_childs[i] = malloc(sizeof(Child));
strncpy((*ptr_to_childs[i]).child_name, "", 16);
(*ptr_to_childs)[i].candy_of_child = NULL;
}
*ptr_to_child_arr = *ptr_to_childs;
//for (i = 0; i < NumOfKids; i++) {
// free(ptr_to_childs[i]);
//}
//free(ptr_to_childs);
return 0;
}
im calling it from the main in the following manner:
int main(int argc, char** argv) {
//=================================================
if (argc < 3) {
printf("Incorrect number of arguments. Please invoke the program \n\t./program.exe < input.txt> <output.txt> \n");
exit(1);
}
int i, lines, checker = 0;
Candy *test = NULL;
char* name_test = NULL;
char* candy_test = NULL;
char* line = "Tamar,Apple\n";
int* NumLinesFile = NULL;
Child *ArrayOfChild = NULL;
.
.
.
//GetNumLines check
printf("%s\n", argv[0]);
printf("%s\n", argv[1]);
printf("%s\n", argv[2]);
GetNumLines(argv[1], &NumLinesFile);
lines = *NumLinesFile;
*NumLinesFile = NULL;
printf("%d\n", lines);
//=================================================
//AllocateKidsArray check
//AllocateKidsArray(lines, &ArrayOfChild);
AllocateKidsArray(lines, &ArrayOfChild);
//ImportKidsArray check
ImportKidsArray(argv[1], lines, &ArrayOfChild);
for (i = 0; i < lines; i++) {
//ArrayOfChild[i].candy_of_child = (Candy*) malloc(sizeof(Candy*));
printf("%s,%s\n", ArrayOfChild[i].child_name, ArrayOfChild[i].candy_of_child->candy_name);
}
//=================================================
and im statistically get heap/buffer violation
i suspect this function but i dont know what is wrong with it.
after the init of the array i pass it to another function that fills it in:
int ImportKidsArray(char* file_addr, int num_kids, Child** array_of_kids_to_fill) {
//=================================================
//"ImportKidsArray" reads the file and assign each valid line to cell in the array
//Input: 1. string to a location of a file
// 2. int indicating the number of kids
// 3. pointer to an array of children
//Output: 1. return an int value {0}->Success {-1}->Failure
// 2. pointer to an initialized array of childerns
//=================================================
FILE *fp;
char character;
char line[32];
int i = 0, j = 1, checker = 0, arr_count = 0;
char* TempChild = NULL;
char* TempCandy = NULL;
Child *arr = *array_of_kids_to_fill;
fp = fopen(file_addr, "r");
// Check if file exists
if (fp == NULL) {
printf("Could not open file %s", file_addr);
return -1;
}
while (!feof(fp)) {
fgets(line, 32, fp);
checker = ParseLine(line, &TempChild, &TempCandy);
GetCandy(TempCandy, &(arr[arr_count].candy_of_child));
strncpy((arr[arr_count]).child_name, TempChild, 16);
arr_count++;
}
return 0;
}
please if anyone can help, it will save my life :)
You want to change to ArrayOfChild. Passing it's address from main().
Change it by appropriately de-referencing it.
*ptr_to_childs = malloc(NumOfKids * sizeof(Child));
Then do rest of the operation on *ptr_to_childs. That will retain the change that you made in the called function.
Also check the return value of malloc. And free(using free()) the memory dynamically allocated.
If you notice carefully you will see in the ArrayOfChild() function you are working with a local variable Child **ptr_to_childs. You certainly don't want that as that variable will not be alive when the function ends.
Also while (!feof(fp)) is not appropriate to use. Check this link for that.
Another thing is check the return value of char *fgets(char *str, int n, FILE *stream).
On success, the function returns the same str parameter. If the
End-of-File is encountered and no characters have been read, the
contents of str remain unchanged and a NULL is returned.

pass dynamic array of pointers to C function

I want to store each line of the file in an 2D array, and anthor array pointing each line (so I can identify each line), I need to pass this pointers array to a function so I can manipulate my lines, I d'ont know how to do that
I have this code to read and store in the arrays
char ligne[MAX];
//open end test the file
FILE* fichier = fopen("csp.txt","r");
if(fichier == NULL){
printf("can't open the file \n");
return EXIT_FAILURE;
}
//the first line in the file contain number of other lines
fgets(ligne, sizeof(ligne), fichier);
int nbrTaille = strtol(ligne, NULL, 10);
//array of pointers
char (*tab)[nbrTaille] = malloc(nbrTaille * sizeof(ligne));
int i = 0;
//tab array point each line
while(fgets(ligne, sizeof(ligne), fichier)){
if(ligne == NULL) EXIT_FAILURE;
strncpy(tab[i], ligne, strlen(ligne));
printf("line%d : %s\n", i, tab[i]);
i++;
}
//call the funnction by passing array of pointers and the number of lines
allDiff(tab, nbrTaille);
the file I'm reading is
2
1 2
2 3
to receive the array by the function I tried this but it doesn't work
void allDiff(char** T, int taille)
I am always confused with the parenthesies and asterisks. The easier way is to declare a double pointer:
char ** tab;
//you need to take care of errors. I am not doing it for simplicity
//tab = {pointer1, pointer2, pointer3, ...., pointerN} total memory needed N * sizeof(pointer)
tab = malloc(lines* sizeof(tab)); //how many pointers you want
for(i = 0; i < lines; i++){
tab[i] = malloc(MAX); //each string
}
In the end free the memory:
for(i = 0; i < lines; i++){
free(tab[i]);
}
free(tab);
EDIT complete code
char ligne[MAX];
//open end test the file
FILE* fichier = fopen("csp.txt","r");
if(fichier == NULL){
printf("can't open the file \n");
return EXIT_FAILURE;
}
//the first line in the file contain number of other lines
fgets(ligne, sizeof(ligne), fichier);
int nbrTaille = strtol(ligne, NULL, 10);
//array of pointers
//char (*tab)[nbrTaille] = malloc(nbrTaille * sizeof(ligne));
int i = 0;
char **tab;
tab = malloc(nbrTaille * sizeof(tab)); //how many pointers you want
for(i = 0; i < nbrTaille; i++){
//sizeof(ligne) is equal to MAX
tab[i] = malloc(MAX); //each string
}
i = 0;
//tab array point each line
while(fgets(ligne, sizeof(ligne), fichier)){
if(ligne == NULL) EXIT_FAILURE;
strncpy(tab[i], ligne, strlen(ligne));
printf("line%d : %s\n", i, tab[i]);
i++;
}
//call the funnction by passing array of pointers and the number of lines
allDiff(tab, nbrTaille);
void function(char tab[][MAXLEN], ...);
This will do.
For the sake of readbility and sanity, typedef C function pointers before creating arrays or double pointers to them.
/* typedef the function pointer. An ftabptr points to a void function that
takes a char * */
typedef void (*ftabptr)(char *p);
/* create an uninitalised list of twenty of them */
int N = 20;
ftabptr *pointerlist = malloc(N * sizeof(ftabptr));
However I don't think you really want to do this. You can write a
functioning program that does weird things with tables of function
pointers, but normally you use a language other than C if you
want to play that game (Lisp-like languages, etc). The high level
language then often emits C as an intermediate step.

add char **tokens incrementally to char *token in C

I tried many solution for this issue, but none worked properly!
I want to copy value of char** array to a variable of type char*.
char *line;
char **tokens = malloc(....);
So, I tried the following:
for(i=0; i < sizeof(tokens); i++)
strncpy(line, tokens[i], strlen(line));
Or
for(i=0; i < sizeof(tokens); i++)
strncat(line, tokens[i]);
Or
for(i=0; i < sizeof(tokens); i++)
memcpy(line, tokens[i], strlen(line));
My understanding is that tokens[i] would be of type char*, but what I couldn't understand if the error I'm getting.
Segmentation fault (core dumped)
If these ways won't work, how can I do the copying?
Any hints?
char *removesubString(char *path, char **args){
char *dir;
int COUNT;
COUNT = 100;
char **dirs = malloc(sizeof(char*)*COUNT);
int i, position;
for (i = 2; i < sizeof(args); i++) {
if(args[i] == NULL){
break;
}
dir = strtok(path, PATH_DELIM);
position = 0;
while (dir != NULL) {
if(strcmp(dir, args[i]) == 0){
dir = strtok(NULL, PATH_DELIM);
continue;
}
dirs[position] = dir;
position++;
dir = strtok(NULL, PATH_DELIM);
}//end of while
dirs[position] = NULL;
}//end of for
char *line;
line = "";
for (i = 0; i < position; i++) {
strncpy(line, dirs[i], strlen(dirs[i]));
}
return line;
}
The first issue that pops up about your code is that you're wrong with the boundaries:
char *line;
char **tokens = malloc(TOKENS_ARRAY_SIZE);
when you do:
for(i=0; i < sizeof(tokens); i++) {
…
}
it's not returning the size of the allocated memory, but the allocated memory for the tokens pointer itself. From the sizeof manpage:
Returns the size, in bytes, of the object representation of type
It happens that when you do sizeof on a static matrix, it will return the size of the matrix because that's the amount of allocated memory for it. But for a dynamically allocated matrix, it will only return the size of the pointer, i.e. if you do:
char array_static[42];
char* array_dyn = malloc(sizeof(char)*42);
printf("sizeof(array_static) = %d\n", sizeof(array_static));
printf("sizeof(array_dyn) = %d\n", sizeof(array_dyn));
it will return:
sizeof(array_static) = 42
sizeof(array_dyn) = 8
so if the number of items within your dynamic array is less than the returned size of the array's pointer, you'll overflow and you'll get a segfault.
So the right way to handle your situation, is to keep the length of the dynamic array in another variable, update it as you're setting up the size of the allocated memory, and then use that value for iterations.
int tokens_length = 42;
char *line;
char **tokens = malloc(sizeof(char*)*tokens_length);
for(i=0; i < sizeof(tokens_length); i++) {
…
}
so in your case, you should be doing:
// keep somewhere the number of directories that you *can* allocate
int nb_dirs = 100;
char **dirs = malloc(sizeof(char*) * nb_dirs);
…
// keep a pointer on how many directories you've added
int position = 0;
while (dir != NULL) {
…
position++;
// fail loudly if you're adding more directories than you've allocated
// or you might use realloc() to extend the array's length
if (position >= nb_dirs) {
printf("ERROR! Too many directories!");
// RETURN WITH ERROR!
}
…
}
// here you iterate over all the directories you've added
for(i = 0; i <= position; i++){
// here you can do stuff with dirs, and copy only the length of the dirs element
strncpy(<TARGET>, dirs[i], strlen(dirs[i]);
}
Then there's another issue you should think about: in your loop, you're modifying path, given as an argument, where you're strcpy()ing dirs into:
strncpy(path, dirs[i], <LENGTH>);
But that makes little sense, whatever you're trying to do is not what you've written.
Here, considering that the size argument is correctly set, you'd be copying each item of the dirs array into the same variable. So you'd end up having always the last value of the dirs array referenced at the path pointer.
But the issue is that you only have the path pointer, but you know little about how it has been allocated when it's been given to the function. How has it been allocated, and how much memory was allocated? What "useful" size is it (though that one can be guessed with strlen())?
Oh, and finally, don't forget to free() your allocations once you're done with them. Do not leak memory, that's rude! ☺
edit:
ok, here are stuff I can see that are wrong, and some comments about it:
char *removesubString(char *path, char **args){
char *dir;
int COUNT = 100;
char **dirs = malloc(sizeof(char*)*COUNT);
int i, position;
/* for both XXX marks below:
*
* below, sizeof(args) will return the size of the pointer
* not the number of items it contains. You *NEED* to pass
* a "int argc" as parameter to your function, that gives
* the numbers of items in the array.
* Think about why you have argc in the main() function construct:
* int main(int argc, const char** argv)
* _OR_ if the args array of strings is _ALWAYS_ terminated
* by a NULL item, then you should do: */
// int i = 0;
// while(args[i] != NULL) {
// /* do stuff */
// ++i;
// }
for (i = 2; i < sizeof(args) /* XXX */; i++) {
if(args[i] == NULL){ /* XXX */
break;
}
dir = strtok(path, PATH_DELIM);
position = 0;
while (dir != NULL) {
if(strcmp(dir, args[i]) == 0){
dir = strtok(NULL, PATH_DELIM);
continue;
}
/* because within the function you have no guarantee
* on the number of tokens within path, if you have
* more than 100 tokens, you will overflow the dirs array.
* a good idea would be to test whether position is bigger
* than or equal to COUNT, and if it is use realloc to
* extend dirs */
dirs[position] = dir;
position++;
dir = strtok(NULL, PATH_DELIM);
/* you could avoid having twice the former line
* and instead make your loop body being: */
// while (dir != NULL) {
// if(strcmp(dir, args[i]) != 0){
// /* TODO: check position vs COUNT and realloc dirs if necessary */
// dirs[position] = dir;
// ++position;
// }
// dir = strtok(NULL, PATH_DELIM);
// }
}
dirs[position] = NULL;
}
char *line;
line = ""; /* ← here you allocate line with a string of length 1 */
for (i = 0; i < position; i++) {
// so here, you'll write up to the number of characters
// within dirs[i], into a string of length one.
strncpy(line, dirs[i], strlen(dirs[i]));
}
/* And even if it was working you'd be assigning the line
* variable to a new value at each iteration, ending up doing
* something equivalent to the following line, but with "position"
* numbers of iterations: */
// strncpy(line, dirs[position-1], strlen(dirs[position-1]));
/* Don't forget to free the instances you've allocated dynamically
* before leaving the function: */
// free(dirs);
/* And finally there's another issue here, you're returning
* a variable that has been statically allocated above, so that
* when you'll try to use the pointed instance in the calling
* context, that variable won't exist anymore. */
return line;
}
HTH

Resources