with this C code I want to fill a dynamic array of char with the words parsed in each differents text files returned by the readdir function.
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
char *getWord(FILE *fp){
char word[100];
int ch, i=0;
while(EOF!=(ch=fgetc(fp)) && !isalpha(ch))
;//skip
if(ch == EOF)
return NULL;
do{
word[i++] = tolower(ch);
}while(EOF!=(ch=fgetc(fp)) && isalpha(ch));
word[i]='\0';
return strdup(word);
}
int readWords(const char * fn,char ** arr){
char *word;
FILE * fp;
int size=0;
//read first time to get the number of words
fp=fopen(fn,"r");
while(word=getWord(fp)){
size++;
}
fclose(fp);
printf("size:%d\n",size);
arr = (char **) malloc (size * sizeof (char *));
//reopen to insert in dynamic array
fp=fopen(fn,"r");
for (int i = 0; i < size; i++){
arr[i] = (char *) malloc (100 * sizeof (char));
word=getWord(fp);
// printf("%s",word);
strcpy(arr[i],word);
}
fclose(fp);
return size;
}
int main(int narg, char *arg[] )
{
struct dirent *de; // Pointer for directory entry
char absdir[256];
char absfn[256];
FILE * F;
int s;
// opendir() returns a pointer of DIR type.
DIR *dr = opendir(arg[1]);
strcpy(absdir,arg[1]);
strcat(absdir,"/");
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory" );
return 0;
}
while ((de = readdir(dr)) != NULL){
if (de->d_type!=4){ // is file?
strcpy(absfn,absdir);
strcat(absfn,de->d_name);
printf("abs_fn:%s \n",absfn);
char** arr_words;
s=readWords(absfn,&arr_words);
printf("%s number of words:%d\n", absfn,s);
for (int i=0;i<s;i++)
printf("word %d:%s\n",i,arr_words[i]);
//free 2D array
for(int i=0;i<s;i++)
free(arr_words[i]);
free(arr_words);
}
}
closedir(dr);
return 0;
}
the words are well parsed with getWord but i can't find the solution to fill the char **arr passed in argument and to use it latter in the main function.
I want to allocated the char **arr_words dynamically with the following form
arr_words[0]=First word of file text
arr_words[1]=Second word
arr_words[s-1]=Last Word
the Readword function return the number of words read in each files.
thanks
Your bug is a more advanced one of the problem described here: Dynamic memory access only works inside function
arr is a local variable. It's a pointer to the first pointer in an array of pointers. In order to return this to main (hang on tight now), your function need to pass a pointer to a pointer to the first pointer in an array of pointers...
Or in plain C, the dreaded three-star programming, char***. But this is actually a valid use for it, about the only valid use of three levels of indirection that exists.
Alternatively, you can just use the return for the char** and skip this extra level of indirection, which might be more readable.
Which form to use is a bit subjective, but you need to change your function to one of these:
int readWords(const char * fn, char*** arr)
{
...
*arr = malloc (size * sizeof (char *))
...
}
or
char** readWords(const char * fn, int* wordsRead)
{
...
arr = malloc (size * sizeof (char *));
...
*wordsRead = size;
return arr;
}
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
char *getWord(FILE *fp){
char word[100];
int ch, i=0;
while(EOF!=(ch=fgetc(fp)) && !isalpha(ch))
;//skip
if(ch == EOF)
return NULL;
do{
word[i++] = tolower(ch);
}while(EOF!=(ch=fgetc(fp)) && isalpha(ch));
word[i]='\0';
return strdup(word);
}
char** readWords(const char * fn,int *wordsRead){
char *word;
char**arr;
FILE * fp;
int size=0;
//read first time to get the number of words
fp=fopen(fn,"r");
while(word=getWord(fp)){
size++;
}
fclose(fp);
printf("size:%d\n",size);
arr = malloc (size * sizeof (char *));
//reopen to insert in dynamic array
fp=fopen(fn,"r");
for (int i = 0; i < size; i++){
arr[i] = (char *) malloc (100 * sizeof (char));
word=getWord(fp);
// printf("%s",word);
strcpy(arr[i],word);
}
fclose(fp);
*wordsRead = size;
return arr;
}
int main(int narg, char *arg[] )
{
struct dirent *de; // Pointer for directory entry
char absdir[256];
char absfn[256];
FILE * F;
int s;
int wordsRead;
char buffer[100];
// opendir() returns a pointer of DIR type.
DIR *dr = opendir(arg[1]);
strcpy(absdir,arg[1]);
strcat(absdir,"/");
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory" );
return 0;
}
while ((de = readdir(dr)) != NULL){
if (de->d_type!=4){ // is file?
strcpy(absfn,absdir);
strcat(absfn,de->d_name);
printf("abs_fn:%s \n",absfn);
char **arr_words;
arr_words=readWords(absfn,&wordsRead);
printf("%s number of words:%d\n", absfn,wordsRead);
for (int i=0;i<wordsRead;i++){
printf("word %d:%s\n",i,arr_words[i]);
}
//free array of pointers
for(int i=0;i<s;i++)
free(arr_words[i]);
free(arr_words);
}
}
closedir(dr);
return 0;
}
I have the following code which works perfectly when not using malloc, but when I want to add in dynamic memory allocation it says segmentation fault although it compiles without warnings or errors. Why?
Thanks in advance
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 30
#define STR 200
#define MAXLEN 40
struct human { //Va
char name[MAXLEN];
char surname[MAXLEN];
int age;
float weight;
};
int main(int argc, char *argv[]) {
char *dlim= ",", *end = "\n", *stop = NULL;
char *tok, *string;
string = (char *)malloc(sizeof(char) * STR);
int i = 0, j = 0;
struct human man[MAXNUM];
FILE *fin = fopen("data.txt", "r");
if (string == NULL) {
printf("Memory not allocated");
}
if (fin == NULL) {
printf("Cannot open file\n");
exit(0);
}
while (fgets(string, sizeof(string), fin)) {
tok = strtok(string, dlim);
strcpy(man[i].name, tok);
tok = strtok(stop, dlim);
strcpy(man[i].surname,tok);
tok = strtok(stop, dlim);
man[i].age = atoi(tok);
tok = strtok(stop, dlim);
man[i].weight = atof(tok);
i++;
}
fclose(fin);
free(string);
j = i;
i = 0;
while (i < j) {
printf("%s %s %d %f \n", man[i].name, man[i].surname, man[i].age, man[i].weight);
i++;
}
return 0;
}
When you make string an allocated array of char, sizeof(string) no longer gives you the size of the array, it gives you the size of the pointer. Therefore you must change the loop to tell fgets the size of your array:
while (fgets(string, STR, fin)) {
...
Or better, if you reallocate the array to size size:
while (fgets(string, size, fin)) {
...
I'm trying to implement a basic shell, I have several functions within it that deal with strings, trying to find file names, implement something equivalent to *argv[] and so on.
I have strings in main(), which are passed to a function to be populated. Next the program returns to main(), which passes the strings to another function to be acted upon.
I was debugging with lldb and found that I was successfully populating the strings with the correct values in the first function but upon exiting the function, re-entering main() the output_str string was NULL again. I thought strings, since they point to space in memory would retain values. They seem to for all but one case, when flag = 1 in the code below.
I can't figure out what's happening as the values seem to only be lost after the final } of the function.
Edited to add complete code, hope it isn't too large.
The code works with say, cat input.txt but not with cat input.txt>output.txt when I try to redirect the output from stdout to a file
Thank you for your help in advance.
Here is the function .c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
{
fprintf(stdout, "\n");
fflush(stdout);
}
}
int check_redirect(char *line, int flag)
{
int n = 0;
if (line == NULL) return (flag);
else
{
do
{
if (line[n] == '>') flag = 1;
n++;
}while (line[n] != '\0');
}
return (flag);
}
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *sep = " \n";
char *delim = ">\n";
if (line != NULL)
{
temp = strtok(line, delim);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
temp = strtok(NULL, delim);
}
if (flag)
{
count = 0;
strcpy(filename, output_str[1]);
output_str[1] = NULL;
*saved_stdout = dup(1);
*f = open(filename , O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(*f, 1);
temp = strtok(*output_str[0], sep);
while (temp != NULL)
{
output_str[count] = temp;
//if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
else
{
count = 0;
temp = strtok(line, sep);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
}
}
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *command = malloc(sizeof(char *));
command = output_str[0];
char *name = "HOME";
int ret_val = 0;
pid_t child_pid;
int child_status;
if (command == NULL);
else if (strcmp("cd", command) == 0)
{
if (output_str[1] == NULL) output_str[1] = getenv(name);
ret_val = 0;
ret_val = chdir(output_str[1]);
if (ret_val) perror(NULL);
}
else
{
child_pid = fork ();
if (child_pid == 0)
{
if (debug)
{
system(line);
fprintf(stderr, "Post System Pre Exec\n1:%s\n2:%s\n3:%s\n", line, output_str[0], command);
sleep(2);
}
execvp(command, output_str);
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
fprintf (stdout, "Unknown command\n");
exit (0);
}
else
{
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
signal(SIGINT, sig_handler);
usleep(500000);
//Parent process waits for child to finish
if (debug) fprintf (stderr, "parent waiting\n");
wait(&child_status);
waitpid(child_pid, &child_status, 0);
signal(SIGINT, SIG_DFL);
}
}
Here is the functions .h file:
#ifndef SHELL_H_INCLUDED
#define SHELL_H_INCLUDED
void sig_handler(int signo);
int prompt(char *line, size_t len, ssize_t read);
int check_redirect(char *line, int flag);
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug);
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug);
#endif // LINKLAYER_H_INCLUDED
Below is main.c, where the function is called.
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "shell.h"
int main(void)
{
int debug = 0;
char *line = NULL;
size_t len = 0;
ssize_t read = 0;
int flag = 0;
int f = 0;
int saved_stdout = 0;
do
{
flag = 0;
//read = prompt(line, len, read);
char buffer[15];
time_t now = time(NULL);
strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now) );
fprintf(stdout, "%s # ", buffer);
signal(SIGINT, SIG_IGN);
read = getline (&line, &len, stdin);
signal(SIGINT, SIG_DFL);
flag = check_redirect(line, flag);
char **output_str = malloc(sizeof(char *));
int count = 0;
char* temp = NULL;
char *filename = malloc(sizeof(char *));
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // function call of problem function
com_exec(line, output_str, filename, &f, &saved_stdout, flag, debug);
} while (read != EOF);
if (debug) fprintf(stderr, "parent exiting\n");
else fprintf(stdout, "\n");
return 0;
}
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
This line re-assigns the value of the the local parameter variable output_str, but the new value in no way makes it back to the caller of the string_breakdown function - meaning that the pointer it has will probably be left dangling, and will cause problems when used ("undefined behavior", manifesting in strange program behavior or crashing).
You need to understand that within the function, output_str is a local variable. You can change its value, but that won't affect the value of any variable in the caller.
You call the function from main:
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
main also uses output_str as the variable name, but again, this is a different variable. One variable is local to main, the other is local to string_breakdown, even though they share the same name. Due to the realloc call above, the pointer value in main's output_str will most likely be invalid on return from string_breakdown, because it is not updated to point to the newly allocated memory. That's why you are "losing" the string values on return from the function - the output_str variable in main is no longer actually pointing to the array of strings, which has been moved to a different location via realloc.
Typically you resolve this kind of problem by adding another level of indirection, changing the output_str parameter from a char ** to a char ***:
void string_breakdown(char *line, char ***output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
and
(*output_str)[count] = temp;
and
*output_str = realloc (*output_str, (count + 1) * sizeof (char *) );
and so on. You need to adjust the call in main as well:
string_breakdown(line, &output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
Because you are passing a pointer to main's output_str variable, the called function is now able to modify its value.
You should also understand that string_breakdown as written modifies the string which the line parameter points to. That's because it uses strtok, and strtok replaces delimiters with nul bytes as it processes the string. So, it is odd that you pass this modified line buffer to com_exec after processing it with string_breakdown.
I get several warnings when I try to compile your code; main.c uses fprintf but doesn't #include <stdio.h>, and uses malloc but doesn't #include <stdlib.h>.
your realloc does nothing.
you mean *output_ptr = realloc....
actually it does something, but its really bad
this is also wrong
output_str[count] = temp;
and this
filename = output_str[1];
you need to distinguish - a pointer to your buffer, a pointer to the pointer to your buffer.
char * buffer = *output_str; // to remove the confusion
strcpy(&buffer[count], temp); // assigning pointers doesnt copy things
filename = buffer[1]; // is hat what you mean - filename is one char
H i am building a basic shell in c and i need to know the size of the array i am populating with user input. Here is the code.
/*
* Tp1.c
*
* Created on: 25 janv. 2014
* Author: shong
*/
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
void cd_handler(int argc, char *argv[]);
int lire(char *chaine, int longueur);
char** init_command(char *str);
int main(int argc, char *argv[]) {
//printf("La valeur de argc est: %d", argc);
while(1){
printf("Log710H2014%>");
char str[200];
lire(str, 200);
char** comms = init_command(str);
printf("%s", comms[1]);
if(strcmp(comms[0], "cd") == 0){
int commArgsC = sizeof(comms)/sizeof(comms[0]);
cd_handler(commArgsC, comms);
}else if (strcmp(comms[0], "exit") == 0){
exit(0);
}
}
}
}
void cd_handler(int argc, char *argv[]){
char cwd[256];
char * directory;
if(argc < 2){
directory = getenv("HOME");
}else if (argc == 2){
directory = argv[1];
}else{
exit(1);
}
if (chdir(directory) == -1) {
printf ("chdir failed - %s\n", strerror (errno));
}else{
if (getcwd(cwd, sizeof(cwd)) == NULL)
perror("getcwd() error");
else
printf("current working directory is: %s\n", cwd);
}
}
char** init_command(char* str){
char ** res = NULL;
char * p = strtok (str, " ");
int n_spaces = 0, i;
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL){
exit (-1);
}
res[n_spaces-1] = p;
p = strtok (NULL, " ");
}
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
//print the result
//for (i = 0; i < (n_spaces+1); ++i)
//printf ("res[%d] = %s\n", i, res[i]);
//free the memory allocated
//free (res);
return res;
}
int lire(char *chaine, int longueur)
{
char *positionEntree = NULL;
if (fgets(chaine, longueur, stdin) != NULL)
{
positionEntree = strchr(chaine, '\n');
if (positionEntree != NULL)
{
//*positionEntree = '\0'; // On remplace ce caractère par \0
}
return 1;
}
else
{
return 0; // on renvoie 0 s'il y a eu une erreur
}
}
The problem is that sizeof(comms) always return 8, no matter the number of elements in comm.
comms is a pointer, so on a 64-bit machine it will have a size of 8 bytes. C has no knowledge about the size of what it points to. You'll have to return the size from the function that allocates the storage and keep track of it yourself.
The behavior sizeof is dependent on what type of variable it is applied to.
If the variable is a pointer, as in the question, sizeof simply evaluates to the size of the pointer type in bytes:
int *y; //y points to an int... maybe an array? Who knows?
printf("%d",sizeof(y)); //No idea how y has been allocated. Defaults to sizeof(int*)
If the variable was declared as an array, sizeof returns the size of the entire array. For instance:
int y[4]; //y is exactly four ints in memory
printf("%d",sizeof(y)); //sizeof knows this, and evaluates to sizeof(int)*4
This is why the sizeof(table)/sizeof(table[0]) would work for an array. However, it does not work pointers as demonstrated above. In short, passing an array as an argument destroys any information regarding how much data is in that array, and you must pass the size separately. This is referred to as "array decay."
The difference between pointers and arrays is very subtle. Most of the time, the two can be used interchangeably, but there are two critical differences:
The difference in the behavior of sizeof as discussed previously.
Arrays cannot be assigned as pointers can. This relates to the fact that they are of constant size. For instance:
char **table;
//table can be assigned different values....
table = NULL;
//...multiples times, if wanted
table = malloc(sizeof(char*)*20);
However,
//table is constant
char *table[20];
//it's individual elements can be assigned as usual...
table[0] = malloc(1);
//...but attempts to change where table points to will fail
table = NULL; //This will cause a compilation error.
My program reads a file specified in the argument and prints out each string and its frequency inside the file.
The program works for this file: http://www.cse.yorku.ca/course/3221/dataset1.txt
but not this file: http://www.cse.yorku.ca/course/3221/dataset2.txt.
It gives Segmentation fault (core dumped) error for the second file.
What could be wrong? Please help!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char word[101];
int freq;
} WordArray;
int main(int argc, char *argv[])
{
WordArray *array = malloc(sizeof(WordArray));
FILE *file;
int i = 0;
file = fopen(argv[1], "r");
char *str = (char*) malloc (108);
while(fgets(str, 100, file) != NULL)
{
int pos = 0;
char *word = malloc (100);
while (sscanf(str, "%s%n", word, &pos ) == 1)
{
int j;
for (j = 0; j < i; j++)
{
if (strcmp(array[j].word, word) == 0)
{
array[j].freq = array[j].freq + 1;
break;
}
}
if (j==i)
{
array = (WordArray *) realloc (array, sizeof(WordArray) * (i+1));
strcpy(array[i].word, word);
array[i].freq = 1;
i++;
}
str += pos;
}
}
fclose(file);
int k;
for (k=0; k<i; k++)
{
printf("%s %d\n", array[k].word, array[k].freq);
}
return 0;
}
Several problems:
You increment str as part of the second loop and don't reset it. I think this means your program is slowly walking through memory.
You fail to free word - probably better to allocate it outside the loop and on the stack but that won't cause a crash unless you input is huge and you run out of memory.
You don't need to cast result of malloc for modern compilers (yes, it used to be needed).
May want to check the results of malloc and realloc for safety.
I assume the first item is your problem.