I want to read all .txt files in the directory and add those file names to an array. Catching the text files part is okay but I am having a problem storing those file names inside an array. What is the mistake I've done here? This is my code.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <strings.h>
int main()
{
DIR *p;
struct dirent *pp;
p = opendir ("./");
char file_list[10][10];
char shades[10][10];
int i = 0;
if (p != NULL)
{
while ((pp = readdir (p))!=NULL) {
int length = strlen(pp->d_name);
if (strncmp(pp->d_name + length - 4, ".txt", 4) == 0) {
puts (pp->d_name);
strcpy(shades[i], pp->d_name);
}
}
i = i + 1;
(void) closedir (p);
for(int i=0; i<4; i++){
printf("\n %s", &shades[i]);
}
}
return(0);
}
What seems to be a problem here is that 'strings' in C works much different than in C++ or C# or Python.
To make it work you'll need to alloc memory for each string.
If I understood correctly what you want to do, here's an example:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#define FILE_LIST_MAX 10
int main()
{
DIR *p = opendir("./");
struct dirent *pp;
char **file_list = malloc(FILE_LIST_MAX * sizeof(char*));
int i = 0;
if (p == NULL) {
printf("Could not open current directory" );
return 0;
}
while ((pp = readdir(p)) != NULL) {
int length = strlen(pp->d_name);
printf ("%s\n", pp->d_name);
if(length > 4 && memcmp(pp->d_name + length - 4, ".txt", 4) == 0) {
char filename[length];
sprintf(filename, "%s", pp->d_name);
file_list[i] = malloc(length * sizeof(char));
strcpy(file_list[i], filename);
i++;
}
}
(void) closedir(p);
printf("\n.txt filenames within array");
for(int j = 0; j < i; j++) {
printf("\n%s", file_list[j]);
}
for(int j = 0; j < i; j++) {
free(file_list[j]);
}
free(file_list);
return(0);
}
It's not perfect though as you must manually change file_list capacity in FILE_LIST_MAX
Here's an example output from executing this code:
Much better approach would be implementing a dynamic array of chars which will automatically resizes as necessary.
Related
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
// This program is going to scan all files in the current directory. It will make a tree for every folder
// and the folder will have a subsection of files in the tree format. YES SORTING!
char **word;
int folder[1000];
int filecheck[1000];
int coun = 0;
int e = 0;
int f = 0;
int u = 0;
int p = 20;
void printdir(char *dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL)
{
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL)
{
lstat(entry->d_name,&statbuf);
if (S_ISDIR(statbuf.st_mode)) // Check if it's a directory
{
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
{
continue;
}
word[coun] = malloc(strlen(entry->d_name) + 1);
folder[e] = coun; // Mark where the folder is.
e++;
f++;
strcpy(word[coun++], entry->d_name);
/* Recurse at a new indent level */
printdir(entry->d_name,depth+1);
f--;
}
else
{
if (f == 0)
{
filecheck[u] = coun;
u++;
}
word[coun] = malloc(strlen(entry->d_name) + 1);
strcpy(word[coun++], entry->d_name);
}
}
chdir("..");
closedir(dp);
}
int main(int argc, char* argv[])
{
word = calloc(1000, sizeof(*word));
printdir(".", 0);
printf("now, print the words in the order.\n");
int c = 0;
int l = 0;
for (int i = 0; i < coun; ++i) // Start readjusting the array in alphabetical order.
{
if (i == folder[c]) // If i matches with a folder, then increment and skip sorting.
{
c++;
}
else // If next is a file, then start the sorting.
{
int imin = i;
for (int j = i + 1; j < folder[c]; ++j) // Keep sorting until the folder ends.
{
char word1[1000], word2[1000];
strcpy(word1, word[j]);
strcpy(word2, word[imin]);
for(int p = 0; word1[p]; p++)
{
word1[p] = tolower(word1[p]);
}
for(int p = 0; word2[p]; p++)
{
word2[p] = tolower(word2[p]);
}
if (strcmp(word1, word2) < 0)
{
imin = j;
}
}
char *tmp = word[i];
word[i] = word[imin];
word[imin] = tmp;
}
}
c = 0;
l = 0;
printf(".\n");
for (int i = 0; i < coun; ++i) // Print the array in the specified format.
{
if (i == folder[c]) // If the folder is the same, print start of the folder.
{
printf("- %s\n", word[i]);
c++;
}
else if (i == filecheck[l]) // If it's a file, print the file normally.
{
printf("- %s\n", word[i]);
l++;
}
else // Print the file inside the folder.
{
printf(" - %s\n", word[i]);
}
}
exit(0);
}
My program is supposed to print the current directory in the tree format. It goes through the sorting perfectly fine, except for the final folder it's checking. For some reason, the hw2 works fine, but hw1 does not sort.
now, print the words in the order.
.
- hw2
- find.c
- ls.c
- Makefile
- tree.c
- hw1
- grep.c
- factor.c
- uniq.c
- monster.c
- sort.c
- tree.c
- tree
I feel like I'm missing something, but I can't find out how to make it work. I've tried different methods and non have worked. Is there anything I can do?
I'm currently writing a program that is doing what is a simple task; read a file line by line, parse it, and store the results into an array where the structure would be array[lineNumber][lineElement]. And for the most part, it's working, except for one odd issue that I've ran into.
In the code below, any access to the array that is housing the data outside of the while loop that's populating it, only returns the last entry. This occurs regardless of the key for lineNumber. Basically it acts like it's overwriting, even though within the while loop its accessible just fine. The only two items that I think could be at fault I've outlined in bold, although for char *processData[100];, it shouldn't be an issue as it's stored within an array that's declared outside the while loop (and if I remember right while loops shouldn't have scope?), and the other line **char **processArray[100];
**, it might be the double star for an array of pointers, but returning that to just one star introduces a whole wave of bugs, namely the aforementioned array structure breaks completely.
So in a nutshell, not being a C expert by any means and exhausting my resources for this issue, I wonder if the C coders here might have some advice as to what the heck is going on, and how I can get this to work as intended....if I even can.
As mentioned previously, the code.
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *ifp;
char line[80];
int returnValue = 0;
//Open file
ifp = fopen("dataFile", "rt");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file!\n");
returnValue = 1;
}
int lineCounter = 0;
char **processArray[100];
while(fgets(line, 80, ifp) != NULL) {
char *processData[100];
char *p = strtok(line, " ,\n");
int keyCounter = 0;
while (p != NULL) {
processData[keyCounter] = p;
p = strtok(NULL, " ,\n");
keyCounter++;
}
processArray[lineCounter] = processData;
printf("%d\n", lineCounter);
printf("Inside -> %s\n", processArray[0][0]);
lineCounter++;
}
printf("Outside %s\n", processArray[0][0]);
fclose(ifp);
int i;
int j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
printf("%d-%d => %s\n ", i, j, processArray[i][j]);
}
}
return returnValue;
}
[Just about] everything gets overwritten on the outer while loop, so only the last processed line remains. The intermediate results must be preserved
I've fixed the program with annotations as to the bugs. The style is #if 0 /* original code */ #else /* fixed code */ #endif
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
FILE *ifp;
char line[80];
int returnValue = 0;
//Open file
ifp = fopen("dataFile", "rt");
if (ifp == NULL) {
fprintf(stderr, "Can't open input file!\n");
returnValue = 1;
}
int lineCounter = 0;
char **processArray[100];
// NOTE/BUG: things get lost on each iteration of this loop
while(fgets(line, 80, ifp) != NULL) {
char *processData[100];
char *p = strtok(line, " ,\n");
int keyCounter = 0;
while (p != NULL) {
// NOTE/BUG: p will get overwritten -- so we must save the string
#if 0
processData[keyCounter] = p;
#else
processData[keyCounter] = strdup(p);
#endif
p = strtok(NULL, " ,\n");
keyCounter++;
}
// NOTE/BUG: processData must be duplicated -- it is overwritten
// on the outer loop
#if 0
processArray[lineCounter] = processData;
#else
char **pA = malloc(sizeof(char *) * keyCounter);
processArray[lineCounter] = pA;
for (int copyidx = 0; copyidx < keyCounter; ++copyidx)
pA[copyidx] = processData[copyidx];
#endif
printf("%d\n", lineCounter);
printf("Inside -> %s\n", processArray[0][0]);
lineCounter++;
}
printf("Outside %s\n", processArray[0][0]);
fclose(ifp);
int i;
int j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
printf("%d-%d => %s\n ", i, j, processArray[i][j]);
}
}
return returnValue;
}
processData is being allocated on the stack and the memory address is not valid after you leave the while loop, regardless of you storing it in processArray. You need to allocate from the heap instead (using malloc or some other memory allocation function)
I want to extract different substrings from a file with array of strings. My file resembles this.
abcdxxx
efghijkyyy
lmzzz
ncdslanclsppp
kdfmsqqq
cbskdnsrrr
From the above file I want to extract xxx, yyy, zzz, ppp, qqq, rrr (basically last 3 characters) and store into an array. I refered this link How to extract a substring from a string in C? but not felt feasible because the content in my file is dynamic and might change for next execution. Can someone give a brief on this?
Here is my approach
FILE* fp1 = fopen("test.txt","r");
if(fp1 == NULL)
{
printf("Failed to open file\n");
return 1;
}
char array[100];
while(fscanf(fp1,"%[^\n]",array)!=NULL);
for(i=1;i<=6;i++)
{
array[i] += 4;
}
the content in my file is dynamic and might change for next execution
Then you need realloc or a linked list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *f;
char **arr = NULL;
char s[100];
size_t i, n = 0;
f = fopen("text.txt", "r");
if (f == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
while (fgets(s, sizeof s, f) != NULL) {
arr = realloc(arr, sizeof(*arr) * (n + 1));
arr[n] = calloc(4, 1);
memcpy(arr[n++], s + strlen(s) - 4, 3);
}
fclose(f);
for (i = 0; i < n; i++) {
printf("%s\n", arr[i]);
free(arr[i]);
}
free(arr);
return 0;
}
Output:
xxx
yyy
zzz
ppp
qqq
rrr
If you always want the last 3 characters you can simplify:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *f;
char (*arr)[4] = NULL;
char s[100];
size_t i, n = 0;
f = fopen("text.txt", "r");
if (f == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
while (fgets(s, sizeof s, f) != NULL) {
arr = realloc(arr, sizeof(*arr) * (n + 1));
memcpy(arr[n], s + strlen(s) - 4, 3);
arr[n++][3] = '\0';
}
fclose(f);
for (i = 0; i < n; i++) {
printf("%s\n", arr[i]);
}
free(arr);
return 0;
}
I have to create a function that reads a file called grwords.txt containing around 540000 words which are written in Greek letters.
I have to convert these words to uppercase and fill an array called char **words.
This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <ctype.h>
void fp();
int main(int argc, char *argv[]) {
SetConsoleOutputCP(1253);
fp();
return 0;
}
void fp(){
char **words;
words = malloc(546490 * sizeof(int *));
for (i = 0; i < 546490; i++)
words[i] = malloc(24 * sizeof(int));
FILE *file;
char *word;
size_t cnt;
file = fopen("grwords.txt", "rt");
if (file == NULL){
printf("File cannot be opened.\n");
exit(1);
}
cnt = 0;
while (1==fscanf(file, "%24s",word)){
if (cnt == 546490)
break;
strcpy(words[cnt++], word);
}
fclose(file);
}
I'm still trying to figure out pointers. I know that & makes a pointer from a value and * a value from a pointer. Updated the program and it successfully fills the array with the words from the file! I still have no idea how to convert Greek lowercase to uppercase.
Handling Greek words can be dependent on your platform.
First of all, you need to understand how file handling works. Here is what I wrote:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define bufSize 1024 // max lenght of word
// we are going to receive the .txt from cmd line
int main(int argc, char *argv[])
{
FILE *fp;
// Assume file has max 10 words
const size_t N = 10;
// Allocate a 2D array of N rows
// and bufSize columns.
// You can think of it like an array
// of N strings, where every string
// has, at most, bufSize length.
char buf[N][bufSize];
// make sure we got the .txt
if (argc != 2)
{
fprintf(stderr,
"Usage: %s <soure-file>\n", argv[0]);
return 1;
}
// open the file
if ((fp = fopen(argv[1], "r")) == NULL)
{ /* Open source file. */
perror("fopen source-file");
return 1;
}
// we will use that for toupper()
char c;
// counters
int i = 0, j;
while (fscanf(fp, "%1024s", buf[i]) == 1)
{ /* While we don't reach the end of source. */
/* Read characters from source file to fill buffer. */
// print what we read
printf("%s\n", buf[i]);
j = 0;
// while we are on a letter of word placed
// in buf[i]
while (buf[i][j])
{
// make the letter capital and print it
c = buf[i][j];
putchar (toupper(c));
j++;
}
i++;
printf("\ndone with this word\n");
}
// close the file
fclose(fp);
return 0;
}
For this test.txt file:
Georgios
Samaras
Γιώργος
Σαμαράς
the code would run as:
./exe test.txt
Georgios
GEORGIOS
done with this word
Samaras
SAMARAS
done with this word
Γιώργος
Γιώργος
done with this word
Σαμαράς
Σαμαράς
done with this word
As you can see, I could read the Greek words, but failed to convert them in upper case ones.
Once you got how file handling goes, you need to use wide characters to read a file with Greek words.
So, by just modifying the above code, we get:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
#define bufSize 1024
int main(int argc, char *argv[])
{
setlocale(LC_CTYPE, "en_GB.UTF-8");
FILE *fp;
const size_t N = 15;
wchar_t buf[N][bufSize];
if (argc != 2)
{
fprintf(stderr,
"Usage: %s <soure-file>\n", argv[0]);
return 1;
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen source-file");
return 1;
}
wchar_t c;
int i = 0, j;
while (fwscanf(fp, L"%ls", buf[i]) == 1)
{
wprintf( L"%ls\n\n", buf[i]);
j = 0;
while (buf[i][j])
{
c = buf[i][j];
putwchar (towupper(c));
j++;
}
i++;
wprintf(L"\ndone with this word\n");
}
fclose(fp);
return 0;
}
And now the output is this:
Georgios
GEORGIOS
done with this word
Samaras
SAMARAS
done with this word
Γιώργος
ΓΙΏΡΓΟΣ
done with this word
Σαμαράς
ΣΑΜΑΡΆΣ
done with this word
I see that you may want to create a function which reads the words. If you need a simple example of functions in C, you can visit my pseudo-site here.
As for the 2D array I mentioned above, this picture might help:
where N is the number of rows (equal to 4) and M is the number of columns (equal to 5). In the code above, N is N and M is bufSize. I explain more here, were you can also found code for dynamic allocation of a 2D array.
I know see that you are on Windows. I tested the code in Ubuntu.
For Windows you might want to take a good look at this question.
So, after you read all the above and understand them, you can see what you asked for with dynamic memory management.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
#define bufSize 1024
wchar_t **get(int N, int M);
void free2Darray(wchar_t** p, int N);
int main(int argc, char *argv[])
{
setlocale(LC_CTYPE, "en_GB.UTF-8");
FILE *fp;
const size_t N = 15;
wchar_t** buf = get(N, bufSize);
if (argc != 2)
{
fprintf(stderr,
"Usage: %s <soure-file>\n", argv[0]);
return 1;
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen source-file");
return 1;
}
wchar_t c;
int i = 0, j;
while (fwscanf(fp, L"%ls", buf[i]) == 1)
{
wprintf( L"%ls\n", buf[i]);
j = 0;
while (buf[i][j])
{
c = buf[i][j];
putwchar (towupper(c));
j++;
}
i++;
wprintf(L"\ndone with this word\n");
}
fclose(fp);
// NEVER FORGET, FREE THE DYNAMIC MEMORY
free2Darray(buf, N);
return 0;
}
// We return the pointer
wchar_t **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
wchar_t **table;
table = malloc(N*sizeof(wchar_t *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(wchar_t) );
return table;
}
void free2Darray(wchar_t** p, int N)
{
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}
Note that this code is expected to work on Linux (tested on Ubuntu 12.04), not on Windows (tested on Win 7).
I am working with hashtables for the first time and I think I have a basic understanding of how they work. I am using a hashtable to check to see if a word exists in a file. The program takes in a "dictionary" file and a word check file. The program works fine when I have a small dictionary but when I use a very large one, the words get overwritten. I was hoping to get some insight as to why. Here is my code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <pthread.h>
#include <tgmath.h>
#include <ctype.h>
#include "hashtable_constants.h"
#define HASH_SIZE 500
#define MAX_WORD_SIZE 50
struct hashTable {
int collisions;
char** words;
};
struct hashTable hashTables[HASH_SIZE];
int hashKey(char * str)
{
int key = 0;
for(int j = 0; j <= 51; j++)
{
if(str[j] == '\0')
break;
key += (int)str[j];
}
key = key % HASH_SIZE;
return key;
}
int main(int argc, char** argv)
{
if(argc > 3)
{
fprintf(stderr, "Too many arguments!\n");
return -1;
}
else if(argc < 3)
{
fprintf(stderr, "Not enough arguments!\n");
return -1;
}
FILE *dictionary = fopen(argv[1], "r");
FILE *wordCheck = fopen(argv[2], "r");
if(dictionary == NULL || wordCheck == NULL ) //ensure input file exists
{
fprintf(stderr, "Error accessing input files\n");
return -1;
}
for(int i = 0; i < HASH_SIZE; i++)
{
hashTables[i].collisions = 0;
hashTables[i].words = malloc(HASH_SIZE * MAX_WORD_SIZE);
}
struct stat fileStat1;
struct stat fileStat2;
stat(argv[1], &fileStat1);
stat(argv[2], &fileStat2);
char* dictBuffer = (char*)malloc(fileStat1.st_size + 1);
char* wordCheckBuff = (char*)malloc(fileStat2.st_size + 1);
if (dictBuffer == NULL || wordCheckBuff == NULL)
{
fprintf (stderr, "Memory error");
return -1;
}
fread(dictBuffer, 1, (int)fileStat1.st_size, dictionary);
fread(wordCheckBuff, 1, (int)fileStat2.st_size, wordCheck);
char* word = malloc(MAX_WORD_SIZE + 1);
int count = 0;
for(int i = 0; i < (int)fileStat1.st_size; i++)
{
char c = dictBuffer[i];
if(isspace(c))
{
word[count] = '\0';
char* wordToAdd = word;
int key = hashKey(wordToAdd);
int collisionIndex = hashTables[key].collisions;
hashTables[key].words[collisionIndex] = wordToAdd;
hashTables[key].collisions++;
count = 0;
free(word);
word = malloc(MAX_WORD_SIZE + 1);
//printf("Added: %s to hashtable at key: %d\n",word,key);
}
else
{
word[count] = c;
count++;
}
}
count = 0;
for(int i = 0; i < (int)fileStat2.st_size; i++)
{
char c = wordCheckBuff[i];
if(isspace(c))
{
word[count] = '\0';
char* wordToCheck = word;
int key = hashKey(wordToCheck);
int collisionIndex = hashTables[key].collisions;
int foundWord = 0;
for(int j = 0; j < collisionIndex; j++)
{
if(hashTables[key].words[j] == wordToCheck)
{
printf("%s == %s\n",hashTables[key].words[j], wordToCheck);
foundWord = 1;
break;
}
}
if(foundWord == 0)
printf("Not a word: %s\n", wordToCheck);
/*else
printf("Key: %d -- Is a word: %s\n",key, word);*/
free(word);
word = malloc(MAX_WORD_SIZE + 1);
count = 0;
}
else
{
word[count] = c;
count++;
}
}
for(int i = 0; i < HASH_SIZE; i++)
free(hashTables[i].words);
free(word);
fclose(dictionary);
fclose(wordCheck);
printf("done\n");
return 0;
}
On problem is that in the line:
hashTables[key].words[collisionIndex] = wordToAdd;
You add 'wordToAdd' to the table.
But wordToAdd is equal to word. A few lines later you call
free(word);
So the hash table now holds a pointer to freed memory.
This will lead to all sorts of undefined behaviour in the program, quite possibly seg-faults too. Also it's very likely that since the memory is now 'free', a subsequent call to malloc might return this same pointer again - which you will then fill with another word. Hence you see the overwriting of strings.
You need to review how you use 'malloc' / 'free' generally in the program. If you want a pointer to refer to a valid string, you cannot call 'free' on that pointer during the intended lifetime of that string.
What you want to do is malloc each string, and add the pointers to the hashtable. Then when you've finished with the hashtable, and no longer need the string data, then call 'free' on all the pointers contained within it. In your case, this will probably need to be in your cleanup code at the end of your program's execution.