I am trying to read the file and get file content and store it in 2 element array [0]: is for content [1]: is for NULL value. This code is working correctly when just I want to print it but I want to use as an array:
char ch;
FILE *file;
file = fopen("input.txt","r");
int allocated_size = 10;
int used_size = 0;
char c, *input, *tmp_input;
// allocate our buffer
input = (char*)malloc(allocated_size);
if (input == NULL) {
printf("Memory allocation error");
return 1;
}
while ((c = fgetc(file)) != EOF){
// make sure there's an empty one at the end to avoid
// having to do this check after the loop
if (used_size == allocated_size-1) {
allocated_size *= 2;
tmp_input = (char*)realloc(input, allocated_size);
if (tmp_input == NULL) {
free (input);
printf("Memory allocation error");
return 1;
}
input = tmp_input;
}
input[used_size++] = c;
}
// we are sure that there's a spot for last one
// because of if (used_size == allocated_size-1)
input[used_size] = '\0';
printf("\nEntered string in the file: %s\n", input);
But how can I use "input" like an array:
char *input[] = {"This is string value from file!", NULL};
For this case I can get access to the text in this way: input[0]
So in order to achieve this
char *input[] = {"This is string value from file!", NULL};
If I am understanding correctly from your write-up then declare input as this
char *input[2];
And every time you perform any operation on your string pointer e.g. malloc and re-alloc etc. use input[0] . This way array's first record will contain your text.
The reason behind this, the string in first record means you need array of char pointers.
Related
I am writing a program in c that reads in text from a text file then randomly selects words from the file and if the words are greater than or equal to six it appends the words together, removes the spaces, and finally prints the new word. (I am using the redirect on linux "<" to read in the file)
Example input: "cheese and crackers"
New word should be: cheesecrackers
Here is the code:
int main (void)
{
int ch;
char *ptrChFromFile;
int strSize = 1;
int i;
int numberOfWords = 1;
ptrChFromFile = malloc (sizeof (char));
if (ptrChFromFile == NULL) {
puts ("COULDN'T ALLOICATE MEMORY");
exit (EXIT_FAILURE);
}
while ((ch = getchar ()) != EOF) {
ptrChFromFile =
realloc (ptrChFromFile, (strSize + 1) * sizeof (char));
if (ptrChFromFile == NULL) {
puts ("failed to allocate memory");
exit (EXIT_FAILURE);
}
if (ch == ' ') {
numberOfWords++;
}
ptrChFromFile[strSize] = ch;
strSize++;
}
ptrChFromFile[strSize] = 0;
char **ptrWords = malloc (sizeof (char *) * strSize);
for (i = 0; i < strSize; i++) {
if (ptrChFromFile[i] != ' ') {
ptrWords[i] = &ptrChFromFile[i];
}
else {
ptrWords[i] = 0;
}
}
free (ptrChFromFile);
free (ptrWords);
return 0;
}
The things that I am struggling with are:
1) Am I allocating the correct memory size for the pointers?
2) How can I parse each word by space without using any special methods from the string.h library (like strtok). Then how do I store those words in the pointer *ptrWords?
so ptrWords should look like this:
cheese | and | crackers
0 1 2
Then I want to loop through ptrWords and check if the length of each word in the pointer is greater than or equal to six. If they are store them in the pointer ptrOutputWord.
so then ptrOutputWord should look like this:
cheese | crackers
0 1
Finally, I want to print the values in ptrOutputWord as one word without spaces.
I tried to explain what I want to do exactly. Thank you to anyone that can help in advance.
EDIT: I changed the code to reflect only the piece that should read in the characters, and reallocate the size of the pointer by one each time a new character is read in, but the right amount of memory isn't being allocated.
You have a few issues:
#include <stdio.h>
#include <time.h>
Why this header?
#include <stdlib.h>
int main()
{
char ch, *ptrChFromFile;
int strSize;
This variable needs to have a useful start value.
ptrWordsFromFile = (char*)malloc(sizeof(char));
No need to cast.
if(ptrChFromFile == NULL)
{
puts("COULDN'T ALLOICATE MEMORY");
exit(EXIT_FAILURE);
}
while((ch = getchar()) != EOF)
getchar returns and int, not a char.
{
ptrChFromFile = (char*)realloc(ptrChFromFile, strSize * sizeof(char)+1);
We need one more character than before and extra space for the 0.
You should add the +2 (not +1) to the number of elements: (strSize+2) * sizeof(<any type>)
Normally you should not directly assign the result of realloc to the same pointer. In case it fails, you lose your old pointer value. Again: No cast needed.
if(ptrChFromFile == NULL)
{puts("failed to alloicate memory");}
If it fails, you cannot continue! Exit from the program just as above
*ptrChFromFile = ch;
You put the character to the start of the enlarged buffer. You should add at the end.
strSize++;
}
Now you have a bunch of characters in memory but no termination for the string.
free(ptrChFromFile);
return 0;
}
After fixing it it looks like this:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ch;
char *ptrChFromFile;
int strSize = 0;
ptrWordsFromFile = malloc(sizeof(char));
if (ptrChFromFile == NULL)
{
puts("COULDN'T ALLOICATE MEMORY");
exit(EXIT_FAILURE);
}
while ((ch = getchar()) != EOF)
{
ptrChFromFile = realloc(ptrChFromFile, (strSize+2) * sizeof(char));
if (ptrChFromFile == NULL)
{
puts("failed to allocate memory");
exit(EXIT_FAILURE);
}
ptrChFromFile[strSize] = ch;
strSize++;
}
ptrChFromFile[strSize] = 0;
// Now add detection and storing of separate words
// (You might omit storing words that are too short)
// Select random words and add together.
free(ptrChFromFile);
return 0;
}
I am currently trying to understand how to go through a .txt file in C and I think I have mostly everything worked out but what I need to do is kind of confusing. I need to create an array of Pointers to point to structs.
Each line in my .txt file should have information corresponding to a single struct. Each line should start with a name followed by some float values.
My question is, when I read the lines and parse them using strtok first, how would I get that information in a struct?
second how would I then make the sample pointer at index i point to the struct?
I tried doing the name seperate from the numbers since the numbers need their own special atof conversion since initially it will be a string. However I think this is probably incorrect since I want to read multiple lines, the code I have before the while loop for obtaining the name will only run once so any following lines will not have the name seperated. I can technically delimit my text file as I choose, so maybe I can just seperate the name with a semicolon and the rest spaces?
If this question seems confusing its probably because I am over thinking
Should I be declaring a struct such as : Sample tmp;
I've been reading examples but I can't figure out how to put the information together. Let me know if I declared my array of pointers incorrectly... Which I think I did. I think my the line that says:
sample arr[SIZE] = {NULL}; might be incorrect but I am not sure. if you can help me work out the logic behind all this I would appreciate it. Thanks.
typedef struct sample{
char* name;
int list_len;
float* value_list;
}sample;
void read_and_parse(){
const int SIZE = 1024;
sample* sample = (sample*)malloc(sizeof(sample); //pointer allocation?
FILE* fin;
fin = fopen("record.txt", "r");
if (fin == NULL) {
printf("record.txt could not be opened \n");
exit(1);
}
else {
int i= 0;
sample arr[SIZE] = {NULL}; //here I try to make the array of pointers
char linebuf[SIZE];
token = strtok(linebuf, " "); //grab the first item
while (fgets(linebuf, SIZE, fin) && i<SIZE) {
arr[i] = malloc(sizeof(sample));
arr[i.name] = token;
token = strtok(NULL, " ");
// now parse the linebuf and fill arr[i] with it
i++;
}
Edited: 11/02/2017
any print statements you see are just silly markers I placed for testing and recognizing what is running when I finally get this code compiled
Here is a much better edited version of the code. I think it should work now.
typedef struct sample{
char* name;
int list_len;
float* value_list;
}sample;
void read_and_parse(FILE **fin, sample* arr[]){
const int SIZE = 1024;
if (*fin == NULL) {
printf("record.txt could not be opened \n");
exit(1);
}
else {
printf("successfully opened file\n");
char linebuf[SIZE];
while ( fgets(linebuf, SIZE, fin) ) {
arr[i] = malloc(sizeof(sample));
int floats_per_line = 0;
while(linebuf[i]){
if(linebuf[i] == ' ');
++floats_per_line;
}
arr[i]->list_len = values_per_line;
arr[i]->value_list = (float*)malloc(sizeof(float)*floats_per_line);
arr[i]->name = strdup(strtok(linebuf, ' '));
char* tok;
int j = 0
while(tok = strtok(NULL, ' ')){
arr[i]->value_list[j] = atof(tok);
++j
}
i++;
}
}
fclose(fin);
}
How would I read a line, parse the information and then attribute it to a struct ?
Read with fgets() which converts a line of file input into a string. OP does that well. Then parse the string.
when I read the lines and parse them using strtok first, how (to) get that information in a struct?
Should I be declaring a struct such as : sample tmp;
Pass the string to a helper function to parse it into a sample that can hold any input. So the pointer members of tmp need to point to maximal space.
char name[SIZE];
char f[SIZE/2];
sample tmp = { name, 0, f };
while (i<SIZE && fgets(linebuf, SIZE, fin)) {
if (sample_parse(&tmp, linebuf) == NULL) {
break; // Parsing failed for some reason, perhaps an error message?
}
// Now populate arr[i] with right-sized memory allocations
arr[i].name = strdup(tmp.name); // ToDo: add NULL check
arr[i].list_len = tmp.list_len;
size_t f_size = sizeof *(tmp.value_list) * tmp.list_len;
arr[i].value_list = malloc(f_size); // ToDo: add NULL check
memcpy(arr[i].value_list, tmp.value_list, f_size);
i++;
}
so maybe I can just separate the name with a semicolon and the rest spaces?
Yes. Also allow other white-spaces too.
if I declared my array of pointers incorrectly.
Code does not have an array of pointers anywhere.
Recommend using size_t for array size type.
typedef struct sample {
char* name;
// int list_len;
size_t list_len;
float* value_list;
} sample;
Some untested code for parsing. Parse the line with strtok(). Further parse the number tokens with strtof().
#define sample_NAME_DELIMITER ":"
#define sample_NUMBER_DELIMITER " \n\t\r"
// parse for a name and then 0 or more numbers
static sample *sample_parse(sample *dest, char *linebuf) {
char *s = strtok(linebuf, sample_NAME_DELIMITER);
if (s == NULL) {
return NULL; // no name - TBD on if this is allowed
}
strcpy(dest->name, s);
size_t i = 0;
while ((s = strtok(NULL, sample_NUMBER_DELIMITER)) != NULL) {
char *endptr;
dest->value_list[i] = strtof(s, &endptr);
if (s == endptr || *endptr) {
// conversion failed or extra junk
break;
}
i++;
}
dest->list_len = i;
return dest;
}
void ReadReferenceStream(char * filename) {
char buf[MAXCHAR];
int i;
char* np;
inputfile = fopen(filename, "r");
if(inputfile == NULL)
printf("File is empty!\n");
while((fgets(buf,MAXCHAR,inputfile)) != NULL) {
if(buf[0] == '#' || buf[0] == '\n')
continue;
}
np = strtok(buf," ");
Pages = malloc(atoi(np)*sizeof(int));
That's all I have so far.
I need to first dynamically allocate space for my array (the variable 'np' is how many integers have to be in the array 'Pages'), which I hope I did correctly.
Then, I have skip any lines in the input text file that start with # or the NULL character.
Finally, I need to store the integers into the array Pages, with the exception of the first integer, which is the value for 'np'.
How can I alter my code to get it to work exactly as I have mentioned. I got most of it, I am just struggling to get it to put the integers into the array.
Given what you have so far, and assuming Pages is defined like int *Pages, just read in the remaining integers:
for (i = 0; np = strtok(NULL, " "); ++i) Pages[i] = atoi(np);
How can I create an array of unique strings without knowing how many strings there are until I process the input file? There can be as many as 2 million strings, max length of 50.
My program is something like this. This works for 51 items then overwrites other data. I don't know how to add an element to the array, if possible.
main() {
char *DB_NAMES[51]; // i thought this gave me ptrs to chunks of 51
// but it's 51 pointers!
char *word;
while not eof {
...function to read big string
...function to separate big sting into words
...
processWord(ctr, DB_NAMES, word);
...
}
}
processWord(int ndx, char *array1[], char *word){
...function to find if word already exists...
//if word is new, store in array
array1[ndx]= (char *)malloc(sizeof(51)); // isn't this giving me a char[51]?
strcpy(array1[ndx],word);
...
}
You can first get the number of words in your file using the below logic and when you get the number of words in the file you can initialize the array size with the word count.
#include<stdio.h>
#define FILE_READ "file.txt"
int main()
{
FILE * filp;
int count = 1;
char c;
filp = fopen(FILE_READ, "r");
if(filp == NULL)
printf("file not found\n");
while((c = fgetc(filp)) != EOF) {
if(c == ' ')
count++;
}
printf("worrds = %d\n", count);
return 0;
}
Regards,
yanivx
Better not use a fixed string length; save memory space.
char **DB_NAMES = 0; // pointer to first char * ("string") in array; initially 0
Pass pointer by reference so that it can be altered. Moreover, you'll want the new ctr value in case a new word has been stored.
ctr = processWord(ctr, &DB_NAMES, word);
Change function processWord accordingly.
int processWord(int ndx, char ***array1a, char *word)
{ char **array1 = *array1a;
...function to find if word already exists...
// if word is new, store in array
{
array1 = realloc(array1, (ndx+1)*sizeof*array1); // one more string
if (!array1) exit(1); // out of memory
array1[ndx++] = strdup(word); // store word's copy
*array1a = array1; // return new array
}
return ndx; // return count
}
I'm very new to C and I'm still learning the basics. I'm creating an application that reads in a text file and breaks down the words individually. My intention will be to count the amount of times each word occurs.
Anyway, the last do-while loop in the code below executes fine, and then crashes. This loop prints memory address to this word (pointer) and then prints the word. It accomplishes this fine, and then crashes on the last iteration. My intention is to push this memory address into a singly linked list, albeit once it's stopped crashing.
Also, just a quick mention regarding the array sizes below; I yet figured out how to set the correct size needed to hold the word character array etc because you must define the size before the array is filled, and I don't know how to do this. Hence why I've set them to 1024.
#include<stdio.h>
#include<string.h>
int main (int argc, char **argv) {
FILE * pFile;
int c;
int n = 0;
char *wp;
char wordArray[1024];
char delims[] = " "; // delims spaces in the word array.
char *result = NULL;
result = strtok(wordArray, delims);
char holder[1024];
pFile=fopen (argv[1],"r");
if (pFile == NULL) perror ("Error opening file");
else {
do {
c = fgetc (pFile);
wordArray[n] = c;
n++;
} while (c != EOF);
n = 0;
fclose (pFile);
do {
result = strtok(NULL, delims);
holder[n] = *result; // holder stores the value of 'result', which should be a word.
wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'.
n++;
printf("Pointer value = %d\n", wp); // Prints the address of holder.
printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array.
//sl_push_front(&wp); // Push address onto stack.
} while (result != NULL);
}
return 0;
}
Please ignore the bad program structure, as I mentioned, I'm new to this!
Thanks
As others have pointed out, your second loop attempts to dereference result before you check for it being NULL. Restructure your code as follows:
result = strtok( wordArray, delims ); // do this *after* you have read data into
// wordArray
while( result != NULL )
{
holder[n] = *result;
...
result = strtok( NULL, delims );
}
Although...
You're attempting to read the entire contents of the file into memory before breaking it up into words; that's not going to work for files bigger than the size of your buffer (currently 1K). If I may make a suggestion, change your code such that you're reading individual words as you go. Here's an example that breaks the input stream up into words delimited by whitespace (blanks, newlines, tabs, etc.) and punctuation (period, comma, etc.):
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buffer[1024];
int c;
size_t n = 0;
FILE *input = stdin;
if( argc > 1 )
{
input = fopen( argv[1], "r");
if (!input)
input = stdin;
}
while(( c = fgetc(input)) != EOF )
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
fclose(input);
return 0;
}
No warranties express or implied (having pounded this out before 7:00 a.m.). But it should give you a flavor of how to parse a file as you go. If nothing else, it avoids using strtok, which is not the greatest of tools for parsing input. You should be able to adapt this general structure to your code. For best results, you should abstract that out into its own function:
int getNextWord(FILE *stream, char *buf, size_t bufsize)
{
int c;
size_t n = 0;
while(( c = fgetc(input)) != EOF && n < bufsize)
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buf[n] = 0;
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
if (n == 0)
return 0;
else
return 1;
}
and you would call it like
void foo(void)
{
char word[SOME_SIZE];
...
while (getNextWord(inFile, word, sizeof word))
{
do_something_with(word);
}
...
}
If you expect in your do...while code, that result could be null (this is the condition for loop break), how do you think this code-line:
holder[n] = *result;
must work? It seems to me, that it is the reason for crashing in your program.
Change do while loop to while
use
while (condition)
{
}
instead of
do {
}while(condition)
It is crashing because you are trying to derefrance a NULL pointer result in do while loop.
I work mostly with Objective-C and was just looking at your question for fun, but I may have a solution.
Before setting n=0; after your first do-while loop, create another variable called totalWords and set it equal to n, totalWords can be declared anywhere within the file (except within one of the do-while loops), but can be defined at the top to the else block since its lifetime is short:
totalWords = n;
then you can set n back to zero:
n = 0;
Your conditional for the final do-while loop should then say:
...
} while (n <= ++totalWords);
The logic behind the application will thus say, count the words in the file (there are n words, which is the totalWords in the file). When program prints the results to the console, it will run the second do-while loop, which will run until n is one result past the value of totalWords (this ensures that you print the final word).
Alternately, it is better practice and clearer for other programmers to use a loop and a half:
do {
result = strtok(NULL, delims);
holder[n] = *result;
wp = &holder[n];
printf("Pointer value = %d\n", wp);
printf("Result is \"%s\"\n", result);
//sl_push_front(&wp); // Push address onto stack.
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word
n++; // We only need to increment if we have not reached the last word
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad.
} while (true);