Program compiles in gcc but goes blank and runs forever right before countEven() is called. I believe there is an issue reading in the file butI'm not too sure. I can't seem to get over this problem and it seems to be persistent amongst other problems I will upload later. I have a few more specific problems I need help with tonight, if someone has time and wants to help me.
The function is designed to read in a file, tokenize the entire file and check each token to see if it is an even number.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned int countEven(char strFileName[])
{
FILE *pFile;
char buffer[80];
char delim[] = " ,\t\n";
char* token;
int numb;
unsigned int count = 0;
pFile = fopen(strFileName, "r");
if (pFile == NULL)
printf("ERROR: the file is invalid");
while(fgets(buffer, sizeof(buffer), pFile) != NULL)
{
token = strtok(buffer,delim);
while(token != NULL)
{
numb = atoi(token);
if((numb%2)==0)
count++;
token = (NULL, delim);
}
fclose(pFile);
}
return count;
}
int main(int argc, char* argv[])
{
unsigned int numbEven = 0;
printf("the file is %s \n", argv[1]);
numbEven = countEven(argv[1]);
printf("the number of even digits is %u \n", numbEven);
return(EXIT_SUCCESS);
}
token = (NULL, delim);
This is a statement involving the comma operator(a) that basically sets token to point at the delim string, hence it will never become NULL, resulting in an infinite loop. What you need there is:
token = strtok(NULL, delim);
In addition to that, you're closing the file within the loop that reads and processes lines of that file (or you would be had you not got stuck in the infinite loop). You probably want to do that after the loop (swap the fclose with the closing brace immediately after it).
It may also be a good idea to check argc before blindly using argv in main(). As it stands, running your program without any filename argument will most likely cause a problem since argv[1] will be NULL.
And, finally, a couple of other things to be wary of:
This won't work well if you have lines greater than 78 characters (you need space for the newline and string terminator) characters. Specifically, if you have a number like 1234|567 that's on that boundary (| is the boundary), you will get an even state for the first part of it despite the fact it's odd;
Any non-numeric tokens will be turned into zero by atoi.
Neither of those will matter if you only have numeric tokens and your lines are short enough but it's something to keep in mind.
(a) The expression a, b evaluates both a and b but the result is simply b.
Related
I have the following code which reads from a given input file into and then into struct I have made.
OFFFile ReadOFFFile(OFFFile fileData, FILE* srcFile)
{
int nvert, nfaces;
fscanf(srcFile, "%s\n");
fscanf(srcFile, "%d %d %s\n", &nvert, &nfaces);
fileData.nvert = nvert;
fileData.nfaces = nfaces;
fileData.vertices = (int *) malloc(fileData.nvert * sizeof(float));
fileData.triFaces = (int *) malloc(fileData.nfaces * sizeof(int));
// Print to check correct size was allocated
printf("%d\n", (fileData.nvert * sizeof(float)));
printf("%d\n", (fileData.nfaces * sizeof(int)));
int i;
float ftemp1, ftemp2, ftemp3;
int itemp1, itemp2, itemp3;
fscanf(srcFile, "%f", &ftemp1);
printf("%lf", ftemp1);
fscanf(srcFile, "%f", &ftemp2);
// fscanf(srcFile, " %lf", &ftemp3);
/* for (i = 0; i < nvert; ++i)
{
fscanf(srcFile, "%f %f %f\n", &ftemp1, &ftemp2, &ftemp3);
fileData.vertices[i].x = ftemp1;
fileData.vertices[i].y = ftemp2;
fileData.vertices[i].z = ftemp3;
}
*/
return(fileData);
}
The problem I am having is with the whole last section that is currently in quotes (The 2 fscanf lines above it are me attempting to test). If I have just one float being read it works fine, but when I add the second or third the whole function fails to even run, although it still compiles. I believe it to be caused by the negative sign in the input, but I don't know how I can fix it.
The data is in the form
OFF
4000 7000 0
0.8267261981964111 -1.8508968353271484 0.6781123280525208
0.7865174412727356 -1.8490413427352905 0.7289819121360779
With the floats continuing on for 4000 lines (hence for loop). These are the structs I have made
typedef struct
{
float x;
float y;
float z;
} Point3D;
typedef struct
{
int face1;
int face2;
int face3;
} triFace;
typedef struct
{
int nvert;
int nfaces;
Point3D *vertices;
triFace *triFaces;
} OFFFile;
Text dump of another file with a lot less lines, also does not work in the for loop. Only using this for testing. https://justpaste.it/9ohcc
Your main problem is the first line in the readOFFFile function:
fscanf(srcFile, "%s\n");
This tries to read a string (presumably the string OFF on the first line of the file), but you don't give fscanf any place to store the string, so it crashes. (As an aside, your compiler really should have warned you about this problem. If it didn't, it's old-fashioned, and there are lots of easy mistakes that it's probably not going to warn you about, and learning C is going to be much harder than it ought to be. Or perhaps you just need to find an option flag or checkbox to enable more warnings.)
You can tell fscanf to read and discard something, without storing it anywhere, using the * modifier. Here's a modified version of your program, that works for me.
void ReadOFFFile(OFFFile *fileData, FILE* srcFile)
{
fscanf(srcFile, "%*s");
if(fscanf(srcFile, "%d %d %*s", &fileData->nvert, &fileData->nfaces) != 2) {
exit(1);
}
fileData->vertices = malloc(fileData->nvert * sizeof(Point3D));
fileData->triFaces = malloc(fileData->nfaces * sizeof(triFace));
int i;
for (i = 0; i < fileData->nvert; ++i)
{
if(fscanf(srcFile, "%f %f %f", &fileData->vertices[i].x,
&fileData->vertices[i].y,
&fileData->vertices[i].z) != 3) {
exit(1);
}
}
}
I have made a few other changes. The other fscanf call, that reads three values but only stores two, also needs a * modifier. I check the return value of fscanf to catch errors (via a crude exit) if the input is not as expected. I got rid of the \n characters in the fscanf calls, since they're not necessary, and potentially misleading. I got rid of some unnecessary temporary variables, and I had the readOFFFile function accept a pointer to an OFFFile structure to fill in, rather than passing and returning it.
Here is the main program I tested it with:
int main()
{
OFFFile fd;
FILE *fp = fopen("dat", "r");
ReadOFFFile(&fd, fp);
for (int i = 0; i < fd.nvert; ++i)
printf("%f %f %f\n", fd.vertices[i].x, fd.vertices[i].y, fd.vertices[i].z);
}
This is still an incomplete program: there are several more places where you need to check for errors (opening the file, calling malloc, etc.), and when you do detect an error, you need to at least print a useful error message before exiting or whatever.
One more thing. As I mentioned, those \n characters you had in the fscanf format strings were unnecessary and misleading. To illustrate what I mean, once you get the program working, have it try to read a data file like this:
OFF 2 0
0 0.8267261981964111
-1.8508968353271484 0.6781123280525208
0.7865174412727356 -1.8490413427352905 0.7289819121360779
Totally malformed, but the program reads it without complaint! This is one reason (one of several dozen reasons, actually) why the scanf family of functions is basically useless for most things. These functions claim to "scan formatted data", but their definition of "formatted" is quite loose, in that they actually read free-form input, generally without any regard for line boundaries.
For some advice on graduating beyond scanf and using better, more reliable methods for reading input, see this question. See also this section and this section in some online C programming course notes.
The line:
fscanf(srcFile, "%s\n");
is invoking undefined behavior. The compiler should warn you about that. Once you've invoked UB, there's no point in speculating further about what is happening.
It's not clear to me what you intended that line to do, but if you use %s in a scanf, you need to give it a valid place to write data. You should always check the value returned by scanf to ensure that you have actually read some data, and you should never use "%s" without a width modifier. Perhaps you want something like:
char buf[256];
if( fscanf(srcFile, "%255s ", buf) == 1 ){
/* Do something with the string in buf */
}
From your comment, it seems that you are intending to use that scanf to skip a line. I strongly recommend using a while(fgetc) loop instead of scanf to do that. If you do want to use scanf, you could try something like fscanf(srcFile, "%*s\n"), but beware that it will stop at the first whitespace, and not necessarily consume an entire line. You could also do fscanf(srcFile, "%*[^\n]%*c"); to consume the line, but you are really better off using a fgetc in a while loop.
Addressing title question:
"How do I read multiple floats from one line of a file"
...with suggestions for a non-scanf() approach.
Assuming the file is opened, (and a file pointer) fp is obtained ) , the first two lines are already handled, and values into ints, say the lines value is converted to int lines;
And given your struct definition (modified to use double to accommodate type compatibility in code below):
typedef struct
{
double x;
double y;
double z;
} Point3D;
In a function somewhere here is one way to parse the contents of each data line into the 3 respective struct values using fgets(), strtok() and strtod():
char delim[] = " \n";
char *tok = NULL;
char newLine[100] = {0};
Point3D *point = calloc(lines, sizeof(*point));
if(point)
{
int i = 0;
while(fgets(newLine, sizeof newLine, fp))
{
tok = strtok(newLine, delim);
if(tok)
{
if(parseDbl(tok, &point[i].x))
{
tok = strtok(NULL, delim);
if(tok)
{
if(parseDbl(tok, &point[i].y))
{
tok = strtok(NULL, delim);
if(tok)
{
if(!parseDbl(tok, &point[i].z))
{
;//handle error
}else ;//continue
}else ;//handle error
}else ;//handle error
}else ;//handle error
}else ;//handle error
}else ;//handle error
i++;//increment for next read
}//end of while
}else ;//handle error
Where parseDbl is defined as:
bool parseDbl(const char *str, double *val)
{
char *temp = NULL;
bool rc = true;
errno = 0;
*val = strtod(str, &temp);
if (temp == str)
rc = false;
return rc;
}
I have a buffer that holds a string from a CSV file that I opened and read. I split the string up by using strtok() and split on the " , ". So now my string looks like this:
char buff[BUFFER_SIZE] = "1000" "CAP_SETPCAP" "CAP_NET_RAW"
I want to make comparisons now for each section of the string, but for the life of me I cannot get it to work. I want to be able to do it without hard coding anything meaning I don't want to assume how many spaces I need to move over. For example to start at CAP_SETPCAP I don't want to have to put buff+5. Anybody know a better way to handle this?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
FILE *fp = fopen("csvtest.csv", "r");
char buff[BUFFER_SIZE];
fgets(buff, 1024, fp);
char *csvData = strtok(buff, ",");
while(csvData != NULL){
csvData = strtok(NULL, ",");
}
int i;
while(buff[i] != '\0'){
strcmp(buff, "CAP_NET_RAW")
printf("Match found");
i++;
}
//or I wanted to do string comparison, but I kept getting
//segmentation fault (core dumped)
char *found;
found = strstr(buff, "CAP_NET_RAW");
printf("%s\n", found);
fclose(fp);
return 0;
}
Your code has three different sections. Lets analyze them:
1. The strtok section
You get the data from the file and then you iterate on strtok:
fgets(buff, 1024, fp);
char *csvData = strtok(buff, ",");
while(csvData != NULL){
csvData = strtok(NULL, ",");
}
You seem not interested in what you found in the different positions: in fact csvData is always overwritten with the last token. And at last it is equal to NULL.
The only thing you get is having the commas in the original array buff overwritten with '\0'. Printing buff you will only see "1000", because after this substring there is the string terminator placed by strtok.
2. Searching "CAP_NET_RAW"
You now iterate on buff[i] until the string terminator. But the string terminator is after the first substring "1000"!
int i;
while(buff[i] != '\0'){
strcmp(buff, "CAP_NET_RAW")
printf("Match found");
i++;
}
Furthermore you search for CAP_NET_RAW, but even without the inner-terminators-issue, the comparison would never succeed. That's because (1) the string actually present in buff is "CAP_NET_RAW" (with double quotes); (2) that token is the last of the row, an it sitll will have the trailing '\n' (fgets doesn't remove it).
By the way: I copied the code after your edit, and now there's no check on strcmp() return value. I suppose it is a typo. Note: strcmp returns 0 if the string match.
3. The strstr attempt
Finally you look for the string using the strstr function. That's a clever idea. But as already said before, buff doesn't contain it. Well, the buffer actually do contain it, but string utilities will stop at the first '\0' they found.
char *found;
found = strstr(buff, "CAP_NET_RAW");
printf("%s\n", found);
So found will be NULL, and dereferencing a NULL pointer (that's what %s tells printf to do) will lead to a segmentation fault.
4. Conclusions
As a very simple way to find the only string you care of, I suggest to use only strstr, without using strtok before. Alternatively you can still use strtok, but saving tokens in different strings so that you can access them later.
Currently learning C, Having some trouble with passing c-string tokens into array. Lines come in by standard input, strtok is used to split the line up, and I want to put each into an array properly. an EOF check is required for exiting the input stream. Here's what I have, set up so that it will print the tokens back to me (these tokens will be converted to ASCII in a different code segment, just trying to get this part to work first).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[1024]; //Initialize a char array of 1024 (input limit)
char *token;
char *token_arr[1024]; //array to store tokens.
char *out; //used
int count = 0;
while(fgets(string, 1023, stdin) != NULL) //Read lines from standard input until EOF is detected.
{
if (count == 0)
token = strtok(string, " \n"); //If first loop, Get the first token of current input
while (token != NULL) //read tokens into the array and increment the counter until all tokens are stored
{
token_arr[count] = token;
count++;
token = strtok(NULL, " \n");
}
}
for (int i = 0; i < count; i++)
printf("%s\n", token_arr[i]);
return 0;
}
this seems like proper logic to me, but then i'm still learning. The issue seems to be with streaming in multiple lines before sending the EOF signal with ctrl-D.
For example, given an input of:
this line will be fine
the program returns:
this
line
will
be
fine
But if given:
none of this
is going to work
It returns:
is going to work
ing to work
to work
any help is greatly appreciated. I'll keep working at it in the meantime.
There are a couple of issues here:
You never call token = strtok(string, " \n"); again once the string is "reset" to a new value, so strtok() still thinks it is tokenizing your original string.
strtok is returning pointers to "substrings" inside string. You are changing the contents of what is in string and so your second line effectively corrupts your first (since the original contents of string are overwritten).
To do what you want you need to either read each line into a different buffer or duplicate the strings returned by strtok (strdup() is one way - just remember to free() each copy...)
I need to save every line of text file in c in a variable.
Here's my code
int main()
{
char firstname[100];
char lastname[100];
char string_0[256];
char string[256] = "Vanilla Twilight";
char string2[256];
FILE *file;
file = fopen("record.txt","r");
while(fgets(string_0,256,file) != NULL)
{
fgets(string2, 256, file);
printf("%s\n", string2);
if(strcmp(string, string2)==0)
printf("A match has been found");
}
fclose(file);
return 0;
}
Some lines are stored in the variable and printed on the cmd but some are skipped.
What should I do? When I tried sscanf(), all lines were complete but only the first word of each line is printed. I also tried ffscanf() but isn't working too. In fgets(), words per line are complete, but as I've said, some lines are skipped (even the first line).
I'm just a beginner in programming, so I really need help. :(
You're skipping over the check every odd number of lines, as you have two successive fgets() calls and only one strcmp(). Reduce your code to
while(fgets(string_0,256,file) != NULL)
{
if( ! strcmp(string_0, string2) )
printf("A match has been found\n");
}
FWIW, fgets() reads and stores the trailing newline, which can cause problem is string comparison, you need to take care of that, too.
As a note, you should always check the return value of fopen() for success before using the returned pointer.
I am new to the C programming language and trying to improve by solving problems from the Project Euler website using only C and its standard libraires. I have covered basic C fundamentals(I think), functions, pointers, and some basic file IO but now am running into some issues.
The question is about reading a text file of first names and calculating a "name score" blah blah, I know the algorithm I am going to use and have most of the program setup but just cannot figure out how to read the file correctly.
The file is in the format
"Nameone","Nametwo","billy","bobby","frank"...
I have searched and searched and tried countless things but cannot seem to read these as individual names into an array of strings(I think thats the right way to store them individually?) I have tried using sscanf/fscanf with %[^\",]. I have tried different combos of those functions and fgets, but my understanding of fgets is everytime I call it it will get a new line, and this is a text file with over 45,000 characters all on the same line.
I am unsure if I am running into problems with my misunderstanding of the scanf functions, or my misunderstanding with storing an array of strings. As far as the array of strings goes, I (think) I have realized that when I declare an array of strings it does not allocate memory for the strings themselves, something that I need to do. But I still cannot get anything to work.
Here is the code I have now to try to just read in some names I enter from the command line to test my methods.
This code works to input any string up to buffer size(100):
int main(void)
{
int i;
char input[100];
char* names[10];
printf("\nEnter up to 10 names\nEnter an empty string to terminate input: \n");
for(int i = 0; i < 10; i++)
{
int length = 0;
printf("%d: ", i);
fgets(input, 100, stdin);
length = (int)strlen(input);
input[length-1] = 0; // Delete newline character
length--;
if(length < 1)
{
break;
}
names[i] = malloc(length+1);
assert(names[i] != NULL);
strcpy(names[i], input);
}
}
However, I simply cannot make this work for reading in the formatted strings.
PLEASE advise me as to how to read it in with format. I have previously used sscanf on the input buffer and that has worked fine, but I dont feel like I can do that on a 45000+ char line? Am I correct in assuming this? Is this even an acceptable way to read strings into an array?
I apologize if this is long and/or not clear, it is very late and I am very frustrated.
Thank anyone and everyone for helping, and I am looking forward to finally becoming an active member on this site!
There are really two basic issues here:
Whether scanning string input is the proper strategy here. I would argue not because while it might work on this task you are going to run into more complicated scenarios where it too easily breaks.
How to handle a 45k string.
In reality you won't run into too many string of this size but it is nothing that a modern computer of any capacity can't easily handle. Insofar as this is for learning purposes then learn iteratively.
The easiest first approach is to fread() the entire line/file into an appropriately sized buffer and parse it yourself. You can use strtok() to break up the comma-delimited tokens and then pass the tokens to a function that strips the quotes and returns the word. Add the word to your array.
For a second pass you can do away with strtok() and just parse the string yourself by iterating over the buffer and breaking up the comma tokens yourself.
Last but not least you can write a version that reads smaller chunks of the file into a smaller buffer and parses them. This has the added complexity of handling multiple reads and managing the buffers to account for half-read tokens at the end of a buffer and so on.
In any case, break the problem into chunks and learn with each refinement.
EDIT
#define MAX_STRINGS 5000
#define MAX_NAME_LENGTH 30
char* stripQuotes(char *str, char *newstr)
{
char *temp = newstr;
while (*str)
{
if (*str != '"')
{
*temp = *str;
temp++;
}
str++;
}
return(newstr);
}
int main(int argc, char *argv[])
{
char fakeline[] = "\"Nameone\",\"Nametwo\",\"billy\",\"bobby\",\"frank\"";
char *token;
char namebuffer[MAX_NAME_LENGTH] = {'\0'};
char *name;
int index = 0;
char nameArray[MAX_STRINGS][MAX_NAME_LENGTH];
token = strtok(fakeline, ",");
if (token)
{
name = stripQuotes(token, namebuffer);
strcpy(nameArray[index++], name);
}
while (token != NULL)
{
token = strtok(NULL, ",");
if (token)
{
memset(namebuffer, '\0', sizeof(namebuffer));
name = stripQuotes(token, namebuffer);
strcpy(nameArray[index++], name);
}
}
return(0);
}
fscanf("%s", input) reads one token (a string surrounded by spaces) at a time. You can either scan the input until you encounter a specific "end-of-input" string, such as "!", or you can wait for the end-of-file signal, which is achieved by pressing "Ctrl+D" on a Unix console or by pressing "Ctrl+Z" on a Windows console.
The first option:
fscanf("%s", input);
if (input[0] == '!') {
break;
}
// Put input on the array...
The second option:
result = fscanf("%s", input);
if (result == EOF) {
break;
}
// Put input on the array...
Either way, as you read one token at a time, there are no limits on the size of the input.
Why not search the giant string for quote characters instead? Something like this:
#include <stdio.h>
#include <string.h>
int main(void)
{
char mydata[] = "\"John\",\"Smith\",\"Foo\",\"Bar\"";
char namebuffer[20];
unsigned int i, j;
int begin = 1;
unsigned int beginName, endName;
for (i = 0; i < sizeof(mydata); i++)
{
if (mydata[i] == '"')
{
if (begin)
{
beginName = i;
}
else
{
endName = i;
for (j = beginName + 1; j < endName; j++)
{
namebuffer[j-beginName-1] = mydata[j];
}
namebuffer[endName-beginName-1] = '\0';
printf("%s\n", namebuffer);
}
begin = !begin;
}
}
}
You find the first double quote, then the second, and then read out the characters in between to your name string. Then you process those characters as needed for the problem in question.