I'm trying to read from .txt file until I hit the character "=". Text file is always the same,contains only these strings:
TaskLimit=3
cc pr.c && ./a.out
Sometimes the code works fine and quits the while loop and sometimes it prints "TaskLimit" but then throws "Segmentation fault (core dumped)" error. Any ideas what am I doing wrong? Should I clear the buf[] or something?
char buf[1];
file = open(argv[1], O_RDONLY);
if (file == -1){
perror("Error opening file");
exit(1);
}
while(1){
read(file, buf, 1);
if(buf[0]=='=') {printf("I'm out");break;}
printf("%c",buf[0]);
//further actions
edit:
in the "further actions" I'm trying to convert a char to int and this seems to be the problem:
char limit_char[0];
int limit;
read(file,limit_char,1);
limit=atoi(limit_char[0]);
edit2:
changing this line
limit=atoi(limit_char[0]);
to
limit=atoi(&limit_char);
helped.
The most important part of C programming is checking return values.
In your sample code sample you do it for open(2), but not for read(2) and you should, because not only does it tell if there was an error, it also tells how many bytes have been read. Excerpt from the man page:
On success, the number of bytes read is returned (*zero indicates end of file*),
and the file position is advanced by this number.
That is, knowing that there is nothing more to read - return value of zero - can let you break from the loop in case the user gave you an invalid file.
When you learn C, I suggest (and pretty much every person on this site) to always compile with -Wall -Wextra -Werror. C is a spartan language and mastering it requires discipline. GCC (or whatever your compiler is) would never have let you execute:
limit=atoi(&limit_char);
As the type of &limit_char is effectively char ** and atoi expects a const char *.
atoi requires a NULL-terminated array of char so your array needs 1 more element than you're reading in.
char limit_char[2];
int limit;
read(file,limit_char,1);
limit_char[1]='\0';
limit=atoi(limit_char);
beyond that, you should probably be checking the return value from read to make sure you've actually read something in.
In your code, your refer to argv[1] for the filename, but on the example usage (cc pr.c && ./a.out) you don't specify any filename.
In you read() statement you use a variable plik which is not defined anywhere, use file here, i.e. the variable you used to store the result of `open().
Fix this and it will work.
This declaras an array of length zero which doesn't make much sense. BTW: normally the compiler should emit at least a warning.
char limit_char[0];
this wont work, you need an array of length 1 because you read 1 byte with read:
char limit_char[1];
or rather this:
char limit_char;
...
read(file, &limit_char, 1);
Related
I am trying to read a time like data (i.e. 10:55) from a text file and assign it in such a way that I can do calculations with it. For instance if I want to covert 10 hrs and 55 minutes from 10:55 into minutes:
10*60+55=655. But 10:55 contains ':' so I can't directly assign it to an integer.
So far I was able to solve this problem using atoi(char *ptr)function which coverts the numbers inside a string into integer type data.The code is running just fine but I am not sure how this function works. Because the string "10:55" contains a non numeric value so shouldn't it return junk value immediately when it detects ":".But in my case it returns 10 and then, after I shifted the pointer by 3 places it gives 55.
So it will be really helpful if someone elaborates how this function exactly works.
Finally is there any other way of solving this problem without using atoi() function and only using basic C programming techniques. If yes then please share your code and explanation with me.Thanks a lot for helping. Here is my code:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int hh,mm;
char startingtime[6];
int strtimearr[2];
FILE *start=fopen("start.txt","w");
if(start==NULL)
{
printf("FILE DOES NOT EXIST");
}
printf("START TIME\n");
printf("->HOUR(hh):");
scanf("%d",&hh);
printf("->MINUTE(mm):");
scanf("%d",&mm);
fprintf(start,"%d:%d",hh,mm);
fclose(start);
start = fopen("start.txt", "r");
if(start==NULL)
{
printf("FILE DOES NOT EXIST");
}
fscanf(start, "%s", startingtime);
fclose(start);
//puts(startingtime);
char *s1= startingtime;
strtimearr[0] = atoi(s1);
strtimearr[1] = atoi(s1+3);
printf("Time : %d:%d \nconverted to minute : %d",strtimearr[0],strtimearr[1],(strtimearr[0]*60+strtimearr[1]));
}
It works but is not robust. If the user gives a number greater than 99 for hour or minute, you will write more than 5 bytes to the file. Then at read time you will read past end of startingtime array invoking Undefined Behavious. On the other hand, if hour is less than 10, the minute field will start at position 2 and not 3.
For IO, the rule is be strict when writing and tolerant when reading. So I advise you to use a stricter format for writing: fprintf(start,"%2d:%02d",hh,mm); or fprintf(start,"%02d:%02d",hh,mm); to be consistent for values less than 10.
At read time, you could at least limit size with fscanf(start, "%5s", startingtime); and then decode with sscanf:
int cr = sscanf(startingtime, "%d:%d", strtimearr, strtimearr+1);
Or directly decode at read time with fscanf:
int cr = fscanf(start, "%d:%d", strtimearr, strtimearr+1);
and control that cr is 2 before printing the result.
How to read a time like “10:55” from a text file
You could use fscanf, or combine fgets (or maybe getline(3) or even on Linux readline(3) ...) and sscanf or strtol but then don't forget to test its return value (some int for fscanf etc...). You might be interested by the %n format control string directive to fscanf or sscanf(3) ....
You could, on POSIX or Linux systems, use time(7) facilities. So #include <time.h> then use strptime(3) or getdate(3).
You could read byte by byte and use fgetc. Check for error conditions (at least EOF). Be aware of UTF-8, in 2020 it is almost everywhere ....
Don't forget to check for parsing errors.
A time like 123:456 in your text file probably don't make sense, and you should check for such input mistakes (and probably give at least the line number where such an input does not make sense).
Read at least about errno(3) and perror(3)
Your program should use perror or strerror(3) when fopen fails. Be also aware that stdout is usually line buffered (except in command pipelines). Consider using fflush and/or setvbuf.
Read of course how to debug small programs and what every C programmer should know about undefined behavior. Consider reading the C11 standard n1570 ...
Enable all warnings and debug info when compiling. If you use a recent GCC compiler on your C code, compile it with gcc -Wall -Wextra -g.
The first part of your question, was already answered as a comment.
Regarding the second question, you could use fscanf to read the integer values directly from the file instead of reading a char array and converting it to an int by atoi:
fscanf(start,"%d:%d", &strtimearr[0], &strtimearr[1]);
If fscanf is successful, it returns the count of successfully read items, otherwise EOF is returned.
I'm trying to use "echo FileName.txt | a.c" in terminal and read the data from the file into a array i got in a header file, but the code I have so far is just giving me a infinite loop. I tried storing the info in a local array also but still the same result.
main(int argc, char *argv[]) {
extern char test[];
FILE *fp;
int i = 0;
int c; // was char c; originally
if (argc == 1) {
fp = stdin;
} else {
fp = fopen (argv[1], "r");
}
while ((c = getc(fp)) != EOF) {
test[i] = c;
printf("%c", test[i]);
i++;
}
}
(1) Change variable c to an int so it recognizes EOF.
(2) Don't increment i before your printf or you will be printing junk.
Not sure what you are trying to accomplish with the echo thing.
NOTE: I'm assuming that your program is intended to do what the code in your question actually does, namely read input from a file named by a command-line argument, or from stdin if no command-line argument is given. That's a very common way for programs to operate, particularly on Unix-like systems. Your question and the way you invoke the program suggest that you're doing something quite different, namely reading a file name from standard input. That's an unusual thing to do. If that's really your intent, please update your question to clarify just what you're trying to do.
Given this assumption, the problem isn't in your program, it's in how you're invoking it. This:
echo FileName.txt | a.c
will feed the string FileName.txt as input to your program; the program has no idea (and should have no idea) that it's a file name.
The way to pass a file name to your program is:
a.c FileName.txt
Or, if you want to read the contents of the file from stdin:
a.c < FileName.txt
(In the latter case, the shell will take care of opening the file for you.)
You could read a file name from stdin, but it's rarely the right thing to do.
A few other points (some already pointed out in comments):
An executable file probably shouldn't have a name ending in .c; the .c suffix indicates a C source file.
You should declare main with an explicit return type; as of C99, the "implicit int" rule was removed, and it was never a particularly good idea anyway:
main(int argc, char *argv[]) { /* ... */ }
You're reading the entire contents of the input file into your test array. This is rarely necessary; in particular, if you're just copying an input file to stdout, you don't need to store more than one character at a time. If you do need to store the contents of a file in an array, you'll need to worry about not overflowing the array. You might want to abort the program with an error message if i exceeds the size of the array.
See also the rest of the advice in Jonathan Leffler's comment; it's all good advice (except that I think he misunderstood the purpose of your test array, which you're using to store the contents of the file, not its name).
first time posting here. I have looked at a few other peoples ways to do this, and one of the ways was nearly exactly the same way that I am trying to do. But, it doesn't work for me?
#include<stdio.h>
int main()
{
FILE *file;
char buffer[15];
char *text[12];
file = fopen("Text.txt", "r");
if(!file) {
printf("Failed");
return 1;
}
int count = 0;
while(fgets(buffer,sizeof buffer, file) != NULL) {
printf("%s", buffer);
text[count] = buffer;
count++;
}
printf("\n");
for (count=0;count<10;count++) {
printf("%s\n", text[count]);
}
fclose(file);
return 0;
}
Now on another site (while looking for a solution or help I found this http://www.daniweb.com/software-development/c/threads/316766/storing-string-in-a-array-reading-from-text-file
Where the person has done it the same way as me (apart from obviously slight differences in what they're reading etc).
My text file reads:
The
Quick
Brown
Fox
Jumps
Over
The
Lazy
Dog (all on their own lines).
Basically I want to read the file in line by line and save each line in the next space in the array.
In the code when I use the line
printf("%s", buffer);
It prints out each word of each line okay to the console window.
However, when I print out the contents of the array with the for loop it simply prints out "dog, dog, dog..." for each space in the array.
Can someone help me here? Am I doing it wrong?
You haven't allocated any memory for text. And you have to copy the value of buffer as it changes in each iteration. Something like:
while(fgets(buffer,sizeof buffer, file) != NULL) {
printf("%s", buffer);
text[count] = malloc(strlen(buffer) + 1);
strcpy(text[count], buffer);
count++;
}
Also, check the return value of malloc for allocation failure.
The buffer is always the same address, so all the elements of array text contains the same pointer (or are uninitialized).
You should consider (assuming a POSIX system):
initializing all your arrays by zeroing them (and also initialize all pointers to NULL), e.g. memset(buffer, 0, sizeof(buffer)); (and for your line buffer, clear it also at the end of the loop).
duplicating the read string with strdup i.e. code
text[count] = strdup(buffer);
and don't forget to free that when appropriate. Actually, you should check that strdup did not fail by returning a NULL pointer.
use getline to read a line (don't forget to initialize the pointer, perhaps to NULL and to eventually free it).
end your printf formatting string with a newline \n or else call fflush, notably before any input.
use the error code errno to display a better error message. Or just call perror like
file = fopen("Text.txt", "r");
if (!file) {
perror("fopen Text.txt failed");
exit (EXIT_FAILURE);
}
Take the habit to compile with all warnings and debugging information (e.g. gcc -Wall -g on Linux) and learn how to use the debugger (e.g. gdb), notably try running line by line your program.
You might be interested in coding for a strict (non POSIX) but plain C2011 standard. But then you have much less freedom to use many POSIX functions (like strdup etc...). I leave the boring exercise to code for strict C99 compliance to the reader (remember that C99 does not even know about directories and suppose nearly "flat" filesystems), because I am a Posix and Linux fan and don't care about non Posix systems (in particular I don't care and did not use Windows or Microsoft systems since 1990).
Also, try to read the code of some free software project (e.g. from freecode). You'll learn a lot
There are two problems in the code:
In the while loop you're storing the same pointer (buffer) over and over again into the array of pointers and you are overwriting the buffer contents too. You should probably advance the buffer pointer by the length of each read string.
In the for loop you're destroying the actual line count and potentially dereferencing uninitialized pointers. Don't do that.
I have, as usual, been reading quite a few posts on here. I found a particular useful posts on bus errors in general, see here. My problem is that I cannot understand why my particular code is giving me an error.
My code is an attempt to teach myself C. It's a modification of a game I made when I learned Java. The goal in my game is to take a huge 5049 x 1 text file of words. Randomly pick a word, jumble it and try to guess it. I know how to do all of that. So anyway, each line of the text file contains a word like:
5049
must
lean
better
program
now
...
So, I created an string array in C, tried to read this string array and put it into C. I didn't do anything else. Once I get the file into C, the rest should be easy. Weirder yet is that it complies. My problem comes when I run it with ./blah command.
The error I get is simple. It says:
zsh: bus error ./blah
My code is below. I suspect it might have to do with memory or overflowing the buffer, but that's completely unscientific and a gut feeling. So my question is simple, why is this C code giving me this bus error msg?
#include<stdio.h>
#include<stdlib.h>
//Preprocessed Functions
void jumblegame();
void readFile(char* [], int);
int main(int argc, char* argv[])
{
jumblegame();
}
void jumblegame()
{
//Load File
int x = 5049; //Rows
int y = 256; //Colums
char* words[x];
readFile(words,x);
//Define score variables
int totalScore = 0;
int currentScore = 0;
//Repeatedly pick a random work, randomly jumble it, and let the user guess what it is
}
void readFile(char* array[5049], int x)
{
char line[256]; //This is to to grab each string in the file and put it in a line.
FILE *file;
file = fopen("words.txt","r");
//Check to make sure file can open
if(file == NULL)
{
printf("Error: File does not open.");
exit(1);
}
//Otherwise, read file into array
else
{
while(!feof(file))//The file will loop until end of file
{
if((fgets(line,256,file))!= NULL)//If the line isn't empty
{
array[x] = fgets(line,256,file);//store string in line x of array
x++; //Increment to the next line
}
}
}
}
This line has a few problems:
array[x] = fgets(line,256,file);//store string in line x of array
You've already read the line in the condition of the immediately preceding if statement: the current line that you want to operate on is already in the buffer and now you use fgets to get the next line.
You're trying to assign to the same array slot each time: instead you'll want to keep a separate variable for the array index that increments each time through the loop.
Finally, you're trying to copy the strings using =. This will only copy references, it won't make a new copy of the string. So each element of the array will point to the same buffer: line, which will go out of scope and become invalid when your function exits. To populate your array with the strings, you need to make a copy of each one for the array: allocate space for each new string using malloc, then use strncpy to copy each line into your new string. Alternately, if you can use strdup, it will take care of allocating the space for you.
But I suspect that this is the cause of your bus error: you're passing in the array size as x, and in your loop, you're assigning to array[x]. The problem with this is that array[x] doesn't belong to the array, the array only has useable indices of 0 to (x - 1).
You are passing the value 5049 for x. The first time that the line
array[x] = ...
executes, it's accessing an array location that does not exist.
It looks like you are learning C. Great! A skill you need to master early is basic debugger use. In this case, if you compile your program with
gcc -g myprogram.c -o myprogram
and then run it with
gdb ./myprogram
(I am assuming Linux), you will get a stack dump that shows the line where bus error occurred. This should be enough to help you figure out the error yourself, which in the long run is much better than asking others.
There are many other ways a debugger is useful, but this is high on the list. It gives you a window into your running program.
You are storing the lines in the line buffer, which is defined inside the readFile function, and storing pointers to it in the arary. There are two problems with that: you are overwriting the value everytime a new string is read and the buffer is in the stack, and is invalid once the function returns.
You have at least a few problems:
array[x] = fgets(line,256,file)
This stores the address of line into each array element. line in no longer valid when readFile() returns, so you'll have an array of of useless pointers. Even if line had a longer lifetime, it wouldn't be useful to have all your array elements having the same pointer (they'd each just point to whatever happened to be written in the buffer last)
while(!feof(file))
This is an antipattern for reading a file. See http://c-faq.com/stdio/feof.html and "Using feof() incorrectly". This antipattern is likely responsible for your program looping more than you might expect when reading the file.
you allocate the array to hold 5049 pointers, but you simply read however much is in the file - there's no checking for whether or not you read the expected number or to prevent reading too many. You should think about allocating the array dynamically as you read the file or have a mechanism to ensure you read the right amount of data (not too little and not too much) and handle the error when it's not right.
I suspect the problem is with (fgets(line,256,file))!=NULL). A better way to read a file is with fread() (see http://www.cplusplus.com/reference/clibrary/cstdio/fread/). Specify the FILE* (a file stream in C), the size of the buffer, and the buffer. The routine returns the number of bytes read. If the return value is zero, then the EOF has been reached.
char buff [256];
fread (file, sizeof(char), 256, buff);
I'm trying to read in a text file line by line and process each character individually.
For example, one line in my text file might look like this:
ABC XXXX XXXXXXXX ABC
There will always be a different amount of spaces in the line. But the same number of characters (including spaces).
This is what I have so far...
char currentLine[100];
fgets(currentLine, 22, inputFile);
I'm then trying to iterate through the currentLine Array and work with each character...
for (j = 0; j<22; j++) {
if (¤tLine[j] == 'x') {
// character is an x... do something
}
}
Can anyone help me with how I should be doing this?
As you can probably tell - I've just started using C.
Something like the following is the canonical way to process a file character by character:
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *fp;
int c;
if (argc != 2) {
fprintf(stderr, "Usage: %s file.txt\n", argv[0]);
exit(1);
}
if (!(fp = fopen(argv[1], "rt"))) {
perror(argv[1]);
exit(1);
}
while ((c = fgetc(fp)) != EOF) {
// now do something with each character, c.
}
fclose(fp);
return 0;
}
Note that c is declared int, not char because EOF has a value that is distinct from all characters that can be stored in a char.
For more complex parsing, then reading the file a line at a time is generally the right approach. You will, however, want to be much more defensive against input data that is not formatted correctly. Essentially, write the code to assume that the outside world is hostile. Never assume that the file is intact, even if it is a file that you just wrote.
For example, you are using a 100 character buffer to read lines, but limiting the amount read to 22 characters (probably because you know that 22 is the "correct" line length). The extra buffer space is fine, but you should allow for the possibility that the file might contain a line that is the wrong length. Even if that is an error, you have to decide how to handle that error and either resynchronize your process or abandon it.
Edit: I've added some skeleton of an assumed rest of the program for the canonical simple case. There are couple of things to point out there for new users of C. First, I've assumed a simple command line interface to get the name of the file to process, and verified using argc that an argument is really present. If not, I print a brief usage message taking advantage of the content of argv[0] which by convention names the current program in some useful way, and exit with a non-zero status.
I open the file for reading in text mode. The distinction between text and binary modes is unimportant on Unix platforms, but can be important on others, especially Windows. Since the discussion is of processing the file a character at a time, I'm assuming that the file is text and not binary. If fopen() fails, then it returns NULL and sets the global variable errno to a descriptive code for why it failed. The call to perror() translates errno to something human-readable and prints it along with a provided string. Here I've provided the name of the file we attempted to open. The result will look something like "foo.txt: no such file". We also exit with non-zero status in this case. I haven't bothered, but it is often sensible to exit with distinct non-zero status codes for distinct reasons, which can help shell scripts make better sense of errors.
Finally, I close the file. In principle, I should also test the fclose() for failure. For a process that just reads a file, most error conditions will already have been detected as some kind of content error, and there will be no useful status added at the close. For file writing, however, you might not discover certain I/O errors until the call to fclose(). When writing a file it is good practice to check return codes and expect to handle I/O errors at any call that touches the file.
You don't need the address operator (&). You're trying to compare the value of the variable currentLine[j] to 'x', not it's address.
ABC XXXX XXXXXXXX ABC has 21 characters. There's also the line break (22 chars) and the terminating null byte (23 chars).
You need to fgets(currentLine, 23, inputFile); to read the full line.
But you declared currentLine as an array of 100. Why not use all of it?
fgets(currentLine, sizeof currentLine, inputFile);
When using all of it, it doesn't mean that the system will put more than a line each time fgets is called. fgets always stops after reading a '\n'.
Try
while( fgets(currentLine, 100, inputFile) ) {
for (j = 0; j<22; j++) {
if (/*&*/currentLine[j] == 'x') { /* <--- without & */
// character is an x... do something
}
}
}