I am kind of new when it comes to C. Took a class on it in college but I just don't practice it much. Well my issue that I'm having is that I'm trying to take an text file and convert it into an array. I have been able to get the text file and print it into the console but when I save run the while statement to read each line, my whole array gets overwritten. For instance if my last line on my text file is 19, my array[0] gets over written to what should be on array[18].
I know the indentations are off a off, coding is a mess, and forgive me on the printf commands, I'm only using them to troubleshoot my code. The text file will have IP address on each line.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#define MAX_LINE_LENGTH 16
int main()
{
int lineCntPOSlist = 0;
int lineCnt = 0;
int i = 0;
FILE *textfile;
char line[MAX_LINE_LENGTH];
char* posList[50];
textfile = fopen("pos-list.txt", "r");
if(textfile == NULL)
{
int posListExist = 0;
system("cls");
printf("File Exist %d\n", posListExist);
fprintf(stderr, "**File open failed\n Make sure there is a pos-list.txt file");
return 1;
}
system("cls");
while(fgets(line, MAX_LINE_LENGTH, textfile))
{
printf("Line %d: %s",lineCnt , line);
posList[lineCnt] = line;
printf("posList[%d] = %s\n", lineCnt, posList[lineCnt] );
printf("posList[0] = %s\n", posList[0] );
lineCnt = ++lineCnt;
lineCntPOSlist = ++lineCntPOSlist;
}
fclose(textfile);
return 0;
}
This:
posList[lineCnt] = line;
simply sets posList[lineCnt] to point at the line buffer in line, it copies zero characters of actual data. In higher-level languages where strings have a bit more presence, this would make sense, but in C it doesn't.
Since there is only one line buffer, it will always hold the characters making up the most recently loaded line, and thus it will act as if previous lines are being "overwritten".
There are several solutions, here are a few:
Make posList into a proper array of strings, but that requires you to decide max length in advance and will waste the space for shorter lines.
Use something like strdup() to allocate copies on the heap of each line, and store pointers to those.
Use a more "proper" reallocating array for the storage and store line pointers (or offsets, which might be better suited due to the reallocating) in the array for easier access.
Related
Wondering if I could get some advice. Firstly, I am very new to programming, so I apologise for any silly mistakes. Please feel free to point them out and I will try to go research to improve.
I feel I am doing something fundamentally wrong with my array.
I am trying to read in from a file whose filename is specified by user input, store the information from the file in a 2D array, which I then plan to print into another file, again defined by user input.
I am currently printing out the array, to check that it has been stored, but I believe I am using the 2D array incorrectly, as when I try to fprintf into my file, it just does not work.
Any advice would be greatly appreciated.
Thank you. Code as follows:
#include <stdio.h>
#include <string.h>
int main()
{
char finame[100];
printf("Enter file you would like to open: ");
scanf("%s", finame);
FILE *in = fopen(finame, "r");
char foname[100];
printf("Enter the filename you would like the output included in: ");
scanf("%s", foname);
FILE *out = fopen(foname, "w");
/*Char array to store string */
char str[50][20];
int i =0;
/*Loop for reading the file till end*/
while((fgets(str[i],sizeof(str[i]), in)) != NULL) {
fputs(str[i++],stdout);
//getchar();
}
return 0;
}
Avoid mixing fgets(), scanf() calls. scanf() leaves a newline character in the input buffer which is later consumed by fgets() (doesn't
matter in this case since input comes from a file not from stdin but a good practice overall).
There is also no protection for overflow, if you want to stick to scanf() add a width specifier and check the result to see if it succeeded.
if (scanf("%99s", finame) != 1) /* save one byte for \0 */
{
/* handle error case */
}
Check that you don't exceed the size of your array while writing to it.
Added 2 define directives that could clean your code up.
#define MAX_LINES 50
#define MAX_CHAR 20
char str[MAX_LINES][MAX_CHAR];
int i = 0;
while (i < MAX_LINES && (fgets(str[i], MAX_CHAR, in)) != NULL) /* always check if running out bounds */
{
fputs(str[i++], stdout);
}
The problem with the above code is that, if the file gets too big, you will end up missing data, what you could do is have a dynamic array and use a malloc / realloc approach to expand the array or a linked list.
I have read a lot of questions on this, and using them I have altered my code and have created code which I thought would work.
I think it's my understanding of C, which is failing me here as I can't see where I'm going wrong.
I get no compilation errors, but when I run i receive 'FileReader.exe has stopped working' from the command prompt.
My code is :
void storeFile(){
int i = 0;
char allWords [45440][25];
FILE *fp = fopen("fileToOpen.txt", "r");
while (i <= 45440){
char buffer[25];
fgets(buffer, 25, fp);
printf("The word read into buffer is : %s",buffer);
strcpy(allWords[i], buffer);
printf("The word in allWords[%d] is : %s", i, allWords[i]);
//allWords[i][strlen(allWords[i])-1] = '\0';
i = i + 1;
}
fclose(fp);
}
There are 45440 lines in the file, and no words longer than 25 char's in length. I'm trying to read each word into a char array named buffer, then store that buffer in an array of char arrays named allWords.
I am trying to get this part working, before I refactor to return the array to the main method (which I feel won't be a fun experience).
You are trying to allocate more than a megabyte (45440*25) worth of data in automatic storage. On many architectures this results in stack overflow before your file-reading code even gets to run.
You can work around this problem by allocating allWords statically, like this
static char allWords [45440][25];
or dynamically, like this:
char (*allWords)[25] = malloc(45440 * sizeof(*allWords));
Note that using buffer in the call to fgets is not required, because allWords[i] can be used instead, without strcpy:
fgets(allWords[i], sizeof(*allWords)-1, fp);
Also note that an assumption about file size is unnecessary: you can continue calling fgets until it returns NULL; this indicates that the end of the file has been reached, so you can exit the loop using break.
I'm working on a project and I just encountered a really annoying problem. I have a file which stores all the messages that my account received. A message is a data structure defined this way:
typedef struct _message{
char dest[16];
char text[512];
}message;
dest is a string that cannot contain spaces, unlike the other fields.
Strings are acquired using the fgets() function, so dest and text can have "dynamic" length (from 1 character up to length-1 legit characters). Note that I manually remove the newline character after every string is retrieved from stdin.
The "inbox" file uses the following syntax to store messages:
dest
text
So, for example, if I have a message from Marco which says "Hello, how are you?" and another message from Tarma which says "Are you going to the gym today?", my inbox-file would look like this:
Marco
Hello, how are you?
Tarma
Are you going to the gym today?
I would like to read the username from the file and store it in string s1 and then do the same thing for the message and store it in string s2 (and then repeat the operation until EOF), but since text field admits spaces I can't really use fscanf().
I tried using fgets(), but as I said before the size of every string is dynamic. For example if I use fgets(my_file, 16, username) it would end up reading unwanted characters. I just need to read the first string until \n is reached and then read the second string until the next \n is reached, this time including spaces.
Any idea on how can I solve this problem?
#include <stdio.h>
int main(void){
char username[16];
char text[512];
int ch, i;
FILE *my_file = fopen("inbox.txt", "r");
while(1==fscanf(my_file, "%15s%*c", username)){
i=0;
while (i < sizeof(text)-1 && EOF!=(ch=fgetc(my_file))){
if(ch == '\n' && i && text[i-1] == '\n')
break;
text[i++] = ch;
}
text[i] = 0;
printf("user:%s\n", username);
printf("text:\n%s\n", text);
}
fclose(my_file);
return 0;
}
As the length of each string is dynamic then, if I were you, I would read the file first for finding each string's size and then create a dynamic array of strings' length values.
Suppose your file is:
A long time ago
in a galaxy far,
far away....
So the first line length is 15, the second line length is 16 and the third line length is 12.
Then create a dynamic array for storing these values.
Then, while reading strings, pass as the 2nd argument to fgets the corresponding element of the array. Like fgets (string , arrStringLength[i++] , f);.
But in this way you'll have to read your file twice, of course.
You can use fgets() easily enough as long as you're careful. This code seems to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_MESSAGES = 20 };
typedef struct Message
{
char dest[16];
char text[512];
} Message;
static int read_message(FILE *fp, Message *msg)
{
char line[sizeof(msg->text) + 1];
msg->dest[0] = '\0';
msg->text[0] = '\0';
while (fgets(line, sizeof(line), fp) != 0)
{
//printf("Data: %zu <<%s>>\n", strlen(line), line);
if (line[0] == '\n')
continue;
size_t len = strlen(line);
line[--len] = '\0';
if (msg->dest[0] == '\0')
{
if (len < sizeof(msg->dest))
{
memmove(msg->dest, line, len + 1);
//printf("Name: <<%s>>\n", msg->dest);
}
else
{
fprintf(stderr, "Error: name (%s) too long (%zu vs %zu)\n",
line, len, sizeof(msg->dest)-1);
exit(EXIT_FAILURE);
}
}
else
{
if (len < sizeof(msg->text))
{
memmove(msg->text, line, len + 1);
//printf("Text: <<%s>>\n", msg->dest);
return 0;
}
else
{
fprintf(stderr, "Error: text for %s too long (%zu vs %zu)\n",
msg->dest, len, sizeof(msg->dest)-1);
exit(EXIT_FAILURE);
}
}
}
return EOF;
}
int main(void)
{
Message mbox[MAX_MESSAGES];
int n_msgs;
for (n_msgs = 0; n_msgs < MAX_MESSAGES; n_msgs++)
{
if (read_message(stdin, &mbox[n_msgs]) == EOF)
break;
}
printf("Inbox (%d messages):\n\n", n_msgs);
for (int i = 0; i < n_msgs; i++)
printf("%d: %s\n %s\n\n", i + 1, mbox[i].dest, mbox[i].text);
return 0;
}
The reading code will handle (multiple) empty lines before the first name, between a name and the text, and after the last name. It is slightly unusual in they way it decides whether to store the line just read in the dest or text parts of the message. It uses memmove() because it knows exactly how much data to move, and the data is null terminated. You could replace it with strcpy() if you prefer, but it should be slower (the probably not measurably slower) because strcpy() has to test each byte as it copies, but memmove() does not. I use memmove() because it is always correct; memcpy() could be used here but it only works when you guarantee no overlap. Better safe than sorry; there are plenty of software bugs without risking extras. You can decide whether the error exit is appropriate — it is fine for test code, but not necessarily a good idea in production code. You can decide how to handle '0 messages' vs '1 message' vs '2 messages' etc.
You can easily revise the code to use dynamic memory allocation for the array of messages. It would be easy to read the message into a simple Message variable in main(), and arrange to copy into the dynamic array when you get a complete message. The alternative is to 'risk' over-allocating the array, though that is unlikely to be a major problem (you would not grow the array one entry at a time anyway to avoid quadratic behaviour when the memory has to be moved during each allocation).
If there were multiple fields to be processed for each message (say, date received and date read too), then you'd need to reorganize the code some more, probably with another function.
Note that the code avoids the reserved namespace. A name such as _message is reserved for 'the implementation'. Code such as this is not part of the implementation (of the C compiler and its support system), so you should not create names that start with an underscore. (That over-simplifies the constraint, but only slightly, and is a lot easier to understand than the more nuanced version.)
The code is careful not to write any magic number more than once.
Sample output:
Inbox (2 messages):
1: Marco
How are you?
2: Tarma
Are you going to the gym today?
I am really struggling to understand how character arrays work in C. This seems like something that should be really simple, but I do not know what function to use, or how to use it.
I want the user to enter a string, and I want to iterate through a text file, comparing this string to the first word of each line in the file.
By "word" here, I mean substring that consists of characters that aren't blanks.
Help is greatly appreciated!
Edit:
To be more clear, I want to take a single input and search for it in a database of the form of a text file. I know that if it is in the database, it will be the first word of a line, since that is how to database is formatted. I suppose I COULD iterate through every single word of the database, but this seems less efficient.
After finding the input in the database, I need to access the two words that follow it (on the same line) to achieve the program's ultimate goal (which is computational in nature)
Here is some code that will do what you are asking. I think it will help you understand how string functions work a little better. Note - I did not make many assumptions about how well conditioned the input and text file are, so there is a fair bit of code for removing whitespace from the input, and for checking that the match is truly "the first word", and not "the first part of the first word". So this code will not match the input "hello" to the line "helloworld 123 234" but it will match to "hello world 123 234". Note also that it is currently case sensitive.
#include <stdio.h>
#include <string.h>
int main(void) {
char buf[100]; // declare space for the input string
FILE *fp; // pointer to the text file
char fileBuf[256]; // space to keep a line from the file
int ii, ll;
printf("give a word to check:\n");
fgets(buf, 100, stdin); // fgets prevents you reading in a string longer than buffer
printf("you entered: %s\n", buf); // check we read correctly
// see (for debug) if there are any odd characters:
printf("In hex, that is ");
ll = strlen(buf);
for(ii = 0; ii < ll; ii++) printf("%2X ", buf[ii]);
printf("\n");
// probably see a carriage return - depends on OS. Get rid of it!
// note I could have used the result that ii is strlen(but) but
// that makes the code harder to understand
for(ii = strlen(buf) - 1; ii >=0; ii--) {
if (isspace(buf[ii])) buf[ii]='\0';
}
// open the file:
if((fp=fopen("myFile.txt", "r"))==NULL) {
printf("cannot open file!\n");
return 0;
}
while( fgets(fileBuf, 256, fp) ) { // read in one line at a time until eof
printf("line read: %s", fileBuf); // show we read it correctly
// find whitespace: we need to keep only the first word.
ii = 0;
while(!isspace(fileBuf[ii]) && ii < 255) ii++;
// now compare input string with first word from input file:
if (strlen(buf)==ii && strstr(fileBuf, buf) == fileBuf) {
printf("found a matching line: %s\n", fileBuf);
break;
}
}
// when you get here, fileBuf will contain the line you are interested in
// the second and third word of the line are what you are really after.
}
Your recent update states that the file is really a database, in which you are looking for a word. This is very important.
If you have enough memory to hold the whole database, you should do just that (read the whole database and arrange it for efficient searching), so you should probably not ask about searching in a file.
Good database designs involve data structures like trie and hash table. But for a start, you could use the most basic improvement of the database - holding the words in alphabetical order (use the somewhat tricky qsort function to achieve that).
struct Database
{
size_t count;
struct Entry // not sure about C syntax here; I usually code in C++; sorry
{
char *word;
char *explanation;
} *entries;
};
char *find_explanation_of_word(struct Database* db, char *word)
{
for (size_t i = 0; i < db->count; i++)
{
int result = strcmp(db->entries[i].word, word);
if (result == 0)
return db->entries[i].explanation;
else if (result > 0)
break; // if the database is sorted, this means word is not found
}
return NULL; // not found
}
If your database is too big to hold in memory, you should use a trie that holds just the beginnings of the words in the database; for each beginning of a word, have a file offset at which to start scanning the file.
char* find_explanation_in_file(FILE *f, long offset, char *word)
{
fseek(f, offset, SEEK_SET);
char line[100]; // 100 should be greater than max line in file
while (line, sizeof(line), f)
{
char *word_in_file = strtok(line, " ");
char *explanation = strtok(NULL, "");
int result = strcmp(word_in_file, word);
if (result == 0)
return explanation;
else if (result > 0)
break;
}
return NULL; // not found
}
I think what you need is fseek().
1) Pre-process the database file as follows. Find out the positions of all the '\n' (carriage returns), and store them in array, say a, so that you know that ith line starts at a[i]th character from the beginning of the file.
2) fseek() is a library function in stdio.h, and works as given here. So, when you need to process an input string, just start from the start of the file, and check the first word, only at the stored positions in the array a. To do that:
fseek(inFile , a[i] , SEEK_SET);
and then
fscanf(inFile, "%s %s %s", yourFirstWordHere, secondWord, thirdWord);
for checking the ith line.
Or, more efficiently, you could use:
fseek ( inFile , a[i]-a[i-1] , SEEK_CURR )
Explanation: What fseek() does is, it sets the read/write position indicator associated with the file at the desired position. So, if you know at which point you need to read or write, you can just go there and read directly or write directly. This way, you won't need to read whole lines just to get first three words.
Im currently learning C through random maths questions and have hit a wall. Im trying to read in 1000 digits to an array. But without specifiying the size of an array first i cant do that.
My Answer was to count how many integers there are in the file then set that as the size of the array.
However my program returns 4200396 instead of 1000 like i hoped.
Not sure whats going on.
my code: EDIT
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
FILE* fp;
const char filename[] = "test.txt";
char ch;
int count = 0;
fp = fopen(filename, "r");
if( fp == NULL )
{
printf( "Cannot open file: %s\n", filename);
exit(8);
}
do
{
ch = fgetc (fp);
count++;
}while (ch != EOF);
fclose(fp);
printf("Text file contains: %d\n", count);
return EXIT_SUCCESS;
}
test.txt file:
731671765313306249192251196744265747423553491949349698352031277450632623957831801698480186947885184385861560789112949495459501737958331952853208805511
125406987471585238630507156932909632952274430435576689664895044524452316173185640309871112172238311362229893423380308135336276614282806444486645238749
303589072962904915604407723907138105158593079608667017242712188399879790879227492190169972088809377665727333001053367881220235421809751254540594752243
525849077116705560136048395864467063244157221553975369781797784617406495514929086256932197846862248283972241375657056057490261407972968652414535100474
821663704844031998900088952434506585412275886668811642717147992444292823086346567481391912316282458617866458359124566529476545682848912883142607690042
242190226710556263211111093705442175069416589604080719840385096245544436298123098787992724428490918884580156166097919133875499200524063689912560717606
0588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
Any help would be great.
You forgot to initialize count, so it contains random garbage.
int count = 0;
(But note that with this change it's still not going to work, since %d in a scanf format means read as many digits as you find rather than read a single digit.)
Turn on your compiler's warnings (-Wall), it will tell you that you didn't initialize count, which is a problem: it could contain absolutely anything when your program starts.
So initialize it:
int count = 0;
The other problem is that the scanfs won't do what you want, at all. %d will match a series of digits (a number), not an individual digit. If you do want to do your counting like that, use %c to read individual characters.
Another approach typically used (as long as you know the file isn't being updated) is to use fseek/ftell to seek to the end of the file, get the position (wich will tell you its size), then seek back to the start.
The fastest approach though would be to use stat or fstat to get the file size information from the filesystem.
If you want number of digits thin you tave to do it char-by-char e.g:
while (isdigit(fgetc(file_decriptor))
count++;
Look up fgetc, getc and scanf in manpages, you don't seem to understand whats going on in your code.
The way C initializes values is not specified. Most of the time it's garbage. Your count variable it's not initialized, so it mostly have a huge value like 1243435, try int count = 0.