C: Segmentation Fault when reading from a file - c

I recently started working on this project, and I'm having trouble reading certain things into a global variable. It's for practice with pthreads, which is why I'm using a global variable in the first place. The program is supposed to read in numbers from a file that represent a solved sudoku puzzle, and the text file will be formatted with 9 number characters followed by a new line, nine times. I've made sure that, when running this program, the file is formatted as such. I know that this segment of my code contains the segmentation fault, but I can't tell where. I can only presume that it has something to do with fgets(). However, none of the resources I looked up have anything in them that would make me think that I'm using it incorrectly. It even does this when I resort to using fgetc, reading it in one bit at a time, making accomodations for fgetc returning an int, unlike fgets assigning a string to a variable (in this case, s).
I wouldn't bring it to stack overflow unless I was sure that I couldn't find it; I've been combing over the code for an hour trying to find this seg fault, and it doesn't make any sense to me. I know that the Seg Fault is here because directly after it, it should print out the entire puzzle matrix, but it doesn't make it that far.
int main(int argc, char *argv[]) {
FILE* puzzlefile;
char s[10];
int i=0, j=0, skip;
//open the file passed in via command line
puzzlefile = fopen(argv[1], "r");
for (i=0; i<9; i++){
//get first string of 10 characters
fgets(s,10, puzzlefile);
for (j=0; j<9; i++){
//read the numbers from s into the puzzle 2D
//array, which takes ints. Ignore the 10th
//character, which will be \n
puzzle[j][i] = (int)(s[j]-'0');
}
}
...
}

Your problem seems to be this:
for (j=0; j<9; i++)
^^^
This should be j++, not i++

Related

Looking for a good way to read data from file in C

this is my first question in this site, and I've just started programming, please be patient with me.
I'm having some trouble with this code to read strings and intergers from a file, they are separated by a semicolon ";" and it starts with the number of lines. The file is something like this:
13;
A;15;B;1;0;0;0;
A;9;C;0;3;2;0;
A;9;D;0;4;0;2;
A;3;E;2;3;2;0;
A;7;F;5;5;3;1;
A;5;G;5;7;6;0;
A;13;H;0;0;0;0;
A;1;I;8;1;0;0;
A;1;J;2;2;1;0;
A;6;K;7;3;2;0;
A;5;L;2;4;3;0;
A;12;AA;0;3;2;0;
A;9;BA;0;1;0;0;
What I tried to do was to create a function that would receive a file pointer (fp) and the number of lines that was read in the main function. It would read the file and save the intergers and strings in matrices :
#include<stdio.h>
#include<stdlib.h>
char timesjogos[100][2][100];
int golsjogos[100][3];
int faltasjogos[100][3];
int camajogos[100][3];
int cverjogos[100][3];
int ReadGames(FILE *caminho,int njogos){
printf("starting to read jogos.\n");
int i=0;
while(fscanf(caminho, " %[^;];%d[^;];%[^;];%d[^;];%d[^;];%d[^;];%d[^;];",
timesjogos[i][0], &golsjogos[i][0], timesjogos[i][1], &golsjogos[i][1],
&faltasjogos[i][0], &camajogos[i][0], &cverjogos[i][0]) == 7)
{
if(i < njogos)
i++;
else
break;
}
}
int main()
{
FILE *fp;
int nbets;
fp = fopen("jogos.txt", "r");
if (!fp){
printf ("Error trying to open file.");
}
fscanf(fp, " %d[^;];", &nbets);
ReadGames(fp, nbets);
}
My doubts are about the %[^;]; I used to read each string up to the ; , should I use %d[^;] for the intergers? What is the correct way to do it?
Also, I'm using global variables to save the information read, the problem is that they can be not large enough to save huge amounts of lines (my professor made a 24180 lines file to test our codes). I was thinking about using the number of lines it gives in the first line to make pre-sized matrices inside the function, but how can I return or save it after the function ends?
I'm sorry for the huge code, but I wanted to show all the details. I would be very thankful for your more experienced help :D
The %[^;] notation reads a string consisting of any number of non-semicolons. The parsing stops when a semicolon is encountered. With numbers, the parsing stops at a semicolon anyway; the semicolon is not a part of the representation of a number.
Your use of %d[^;] means that fscanf() is looking for an integer (%d), then an open square bracket, caret, semicolon and close square bracket. These don't appear in the input, of course, so the scanning fails.
Therefore, your input loop should probably be:
while (fscanf(caminho, " %[^;];%d;%[^;];%d;%d;%d;%d;",
timesjogos[i][0], &golsjogos[i][0], timesjogos[i][1],
&golsjogos[i][1], &faltasjogos[i][0], &camajogos[i][0],
&cverjogos[i][0]) == 7)
{
...
}
You might prefer to specify a maximum length for the %[^;] conversion specifications; %99[^;] would be appropriate since the third dimension of timesjogos is 100. There's an off-by-one difference between the length specified and the length used (enshrined because of ancient history; it was that way before the first C standard, and the C standard codified existing practice).

C - Error while running .exe file that I compiled

I used geany to compile my code and no errors were found.
But when I run the .exe file the program stops working, and I'm not a good programmer, this is a work for school.
My program consists of reading 2 words, in this words its going to count how many letters each one has, and then he divides de number of letters in wordA for number of letters in wordB.
This is my code
#include <stdio.h>
int main(int argc, char *argv[])
{
int i, j;
float n;
printf ("Insert first word:\n");
for(i=0; argv[1][i] != '\0'; i++);
printf ("Insert second word:\n");
for(j=0; argv[2][j] != '\0'; j++);
n=i/j;
printf("%.4f", n);
return 0;
}
In this line
n = i/j;
you are performing integer division. So, for example, let's say that i is 3 and j is 5, then you perform 3/5 which equals 0.
But I think you are looking to perform 3.0/5.0 and hoping for the answer 0.6. So you need to perform floating point division. You can force that by casting one of the operands to a float.
n = (float)i/j;
In the question you wrote Int rather than int. I assumed that was a transcription error when asking the question. But perhaps your real code looks like that. In which case, you'll need to change it to int to get it to compile.
The other possible problem you have is that the program expects arguments to be passed on the command line. Are you passing two arguments to your program? In other words you need to execute your program like this:
program.exe firstword secondword
If you are not passing arguments then you will encounter runtime errors when attempting to access non-existent arguments in argv[]. At the very least you should add a check to the program to ensure that argc==3.
If you want to read the input from stdin, rather than passing command line arguments, use scanf.
I think this is a conceptual error. Your program (probably) runs fine when called like this:
myapp word1 word2
But I think you expect it to work like this:
myapp
Insert first word:
> word1
Insert second word:
> word2
But that's not what argv is about. You should look into scanf
Specifically, the error in the second case is because argv[1] is NULL, so argv[1][i] is a bad memory access.

Why is this C code giving me a bus error?

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);

getting numbers from stdin to an array in C

I'm trying to get numbers from stdin to an array. the first number in stdin is the number of elements in the array (the number can be any int).
I did this to get the first number:
while(c=getchar()!=' '){
n*=10;
n+=atoi(c);
}
And then created an array of size n.
Now I need to go through all the rest
while(c=getchar()!=EOF)
and add numbers to the array. The numbers are separated by \t and sometimes \n as well.
How would I do that? I've been thinking for an hour and still haven't got a working code.
Any help?
Thanks!
Unless you're feeling particularly masochistic (or can't due to homework requirements), you'd normally do it using scanf:
int n;
int *numbers;
scanf("%d", &n);
numbers = malloc(n * sizeof(*numbers));
for (int i=0; i<n; i++)
scanf("%d", &numbers[i]);
For more robust error handling, you frequently want to read a line at a time using fgets, then parse that into individual numbers using sscanf (or something similar).
As an aside: no you should not cast the return from malloc to int *. It's neither necessary nor desirable in C. Just #include <stdlib.h>, and assign the result as shown above. If your compiler is giving you a warning (or error) about a conversion, that means one of two things is happening: either you've forgotten to #include <stdlib.h> as required, or else you're actually compiling as C++. If you're writing C++, write real C++, which means you shouldn't be using malloc at all.

Line counting and abberant results

I'm writing a utility to count the lines in a given file via the Unix command line. Normally this would be dead simple for me, but apparently I'm having a major off night. The goal of this program is to take in an unknown number of files from the command line, read them into a buffer and check for the newline character. Sounds simple?
int size= 4096;
int main(int argc, char *argv[]){
int fd, i, j, c, fileLines, totalLines;
char *buf= (char *)malloc(size); //read buffer
for (i=2; i<argc; i++){ //get first file
fileLines=1;
if ((fd=open(argv[i], O_RDONLY))!= -1){ //open, read, print file count, close
while ((c= read(fd, buf, size))!= 0){
for (j=0; j<size; j++){
if (buf[j] == '\n')
fileLines++;
}
}
}
printf("%s had %d lines of text\n", argv[i], fileLines);
totalLines+= fileLines;
close(fd);
}
printf("%d lines were counted overall\n", totalLines);
return 0;
}
I have two problems. The first is that the first printf statement is never executed outside of the debugger. The second thing is the totalLines printout should be roughly 175K lines, but the printed value is about 767 times larger.
I'm having trouble understanding this, because all the relevant variables have been declared out of scope from their modification, but that still doesn't explain why the first print statemeent and line counter update is ignored outside of the debugger along with the abberant totalLines result
Any help is appreciated.
ANSWER
Two changes were suggested.
The first was to change j<size to j<c. While this was not the solution required, it follows good coding convention
The second was to change i=2 to i=1. The reason I had the original start variable was the way I started the debugger executable. In the gdb command line, I entered in run lc1 f1.txt to start the debugger. This resulted in the arglist having three variables, and I didn't know that run f1.txt was perfectly suitable, since my professor introduced us to gdb by using the first example.
You're not initializing totalLines. You increment it inside of your loop, but you don't set it to 0 when you first declare it.
Also, why do you start from i=2? This is the third command-line argument, and the second parameter to your program. Is this what you intended, or did you want to start from the first parameter to your program?
And as others have pointed out, you should have j < c instead of j < size.
Your loop is wrong. It should be j=0; j<c; j++. That's probably not directly responsible for the errors you're seeing but will definitely cause problems.
Did you try stepping through the code with a debugger?
Consider: ./program file.txt
argv[0] is "program"
argv[1] is "file.txt"
which means your for loop starts from the wrong index, and if you are passing only 1 file through the cmd line your code will never enter in that loop! It should start at index 1:
for (i=1; i<argc; i++){
Do yourself a favor and initialize all variables when you declare them. Is the only way to ensure that there will be no garbage on those memory locations.
First, excellent question. :) All the necessary code, well stated, and it's obvious you've done your work. :)
How are you starting your program when in the debugger? I think the argv[2] starting point might be related to not reaching the printf(), but it would depend upon how you're starting. More details below.
A few comments:
int size= 4096;
Typically, C preprocessor macros are used for this kind of magic number. I know your teachers probably said to never use the preprocessor, but idiomatic C would read:
#define SIZE 4096
for (i=2; i<argc; i++){ //get first file
Try i=1 -- argv[0] is the name of the program, argv[1] is going to be the first command line argument -- presumably if someone calls it via ./wc foo you want to count the number of lines in the file foo. :) (Also, you want the loop to terminate. :) Of course, if you're trying to write a replacement for wc -l, then your loop is alright, but not very helpful if someone screws up the arguments. That can safely be kept as a project for later. (If you're curious now, read the getopt(3) manpage. :)
if ((fd=open(argv[i], O_RDONLY))!= -1){
while ((c= read(fd, buf, size))!= 0){
for (j=0; j<size; j++){
You are ending the loop at j<size -- but you only read in c characters in the last block. You're reading left-over garbage on the last block. (I wouldn't be surprised if there are generated files in /proc/ that might return short reads out of convenience for kernel programmers.)
if (buf[j] == '\n')
fileLines++;
}
}
}
printf("%s had %d lines of text\n", argv[i], fileLines);
totalLines+= fileLines;
This is the first time you've assigned to totalLines. :) It is liable to have garbage initial value.
close(fd);
You should probably move the close(fd); call into the if((fd=open())) block; if the open failed, this will call close(-1);. Not a big deal, but if you were checking the close(2) error return (always good practice), it'd return a needless error.
}
Hope this helps!
You're probably aware of wc, but I'll mention it just in case.
I know it doesn't directly help you debug your specific problem, but maybe you could glance at the source code and/or use it to verify that your program is working.
You have logical error in for() loop. You should use "bytes read" instead "read up to", what I mean in your code use "c" instead "size" in for()

Resources