I'm trying to save certain words into a pointer to an array (**valid_words), but I am running into an issue I do not understand. Below is the function I am trying to utilize, end result is to have valid_words contains all the valid words according to the condition when iline and dline are equal.
void CheckFile(char *input_file, char *dictionary_file, char *output_file, char **valid_words)
{
/* Open files as read or append */
FILE *input, *dictionary, *output;
input = fopen(input_file, "r");
dictionary = fopen(dictionary_file, "r");
output = fopen(output_file,"a");
int word_count = 0;
/* Read from files */
if (input != NULL && dictionary!= NULL)
{
char *iline = malloc(MAXSIZE*sizeof(char));
char *dline = malloc(MAXSIZE*sizeof(char));
while (fgets (iline, sizeof iline, input) != NULL)
{
while (fgets (dline, sizeof dline, dictionary) != NULL)
{
trimwhitespace(iline);
trimwhitespace(dline);
if (strcasecmp(iline, dline) == 0 )
{
fprintf(output, "%s\n",iline);
valid_words[word_count] = iline;
printf("Word Count: %d\n", word_count);
printf("At Zero: %s\n", valid_words[0]);
printf("Valid Word: %s\n", valid_words[word_count]);
printf("Actual Word: %s\n", iline);
word_count++;
}
}
rewind(dictionary);
}
fclose(input);
fclose(dictionary);
fclose(output);
free(iline);
free(dline);
}
else
{
printf("An error has occured\n");
}
}
The current output I am getting is
Word Count: 0
At Zero: miles
Valid Word: miles
Actual Word: miles
Word Count: 1
At Zero: limes
Valid Word: limes
Actual Word: limes
Word Count: 2
At Zero: smile
Valid Word: smile
Actual Word: smile
Word Count: 3
At Zero: slime
Valid Word: slime
Actual Word: slime
I am expecting At Zero: to always output "miles", but this is not happening.
After the function has been called printing valid_words[i] results in nothing being printed out.
I will really appreciate it if someone can help me out, and am very open to any criticism. You can find the full implementation here at http://pastebin.com/TjxLRVaC
Thank you.
The answer to why it doesn't work is -
valid_words[word_count] = iline;
You should use either strcpy after ensuring that the element in valid_words can hold up to MAXSIZE characters or use strncat (NB: not strncpy) after ensuring that the first (really zeroth) character in the element in valid_words that you are inserting is '\0'.
Some observations:
Assuming MAXSIZE is a #defined constant, this is better -
char iline[MAXSIZE];
char dline[MAXSIZE;
than the malloc calls that you have (by the way, sizeof(char) is one by definition.)
Likewise, you are better off changing the last parameter of CheckFile to char valid_words[][MAXSIZE] (and thus changing the arguments in all the calls to CheckFile).
Hope this helps.
Related
Hi i'm struggling with understanding what's wrong with my program.
My best guess is something related with this line of code here:
scanf("%s", str);
The thing is i'm trying to call a function that uses a strtok on a String passed on to it typed by the user, all of this inside of a while loop as shown in the code example below:
int i = 0;
char str[80];
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result (not what i want, see further below what i actually want):
Type in some string so i can break it: hey there how are you doing!
hey
Loop 0 ended.
Type in some string so i can break it:
there
Loop 1 ended.
Type in some string so i can break it:
how
Loop 2 ended.
The reason why i think this is caused by the scanf line is because the program works fine when i'm using instead some dummy pre-declared String
int i = 0;
while(i != 3){
char str[80] = "hey there how are you doing!";
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result:
hey
there
how
are
you
doing!
Loop 0 ended.
hey
there
how
are
you
doing!
Loop 1 ended.
hey
there
how
are
you
doing!
Loop 2 ended.
Here's the funtion that uses strtok, most of the code here is taken from https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
int testFunc(char linha[80]){
//
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(linha, s);
/* walk through other tokens */
while(token != NULL) {
printf("%s\n", token);
token = strtok(NULL, s);
}
return 1;
}
I'm puzzled, it's like the program is executing testFunc() in paralel with the main function.
I think the problem is when you execute this loop:
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
scanf gets only one word at a time, so the loop cycles 3 times, you only get 3 words no matter how long the input string is.
On the other hand, in your other example you already have a string to break apart so the function will work.
There are different ways to get spaced strings from the console but here is what I consider to be a good option to do it:
str[MAX_SIZE];
fgets(str, MAX_SIZE, stdin);
// where MAX_SIZE is the maximum size you want to allow for the string,
//must be smaller than str.
According to scanf(3) man page:
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to the initial element of a
character array that is long enough to hold the input sequence
and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at
the maximum field width, whichever occurs first
You can use fgets or fread for input:
char buffer[1000];
/* fgets (reads a line of text with trailing newline */
fgets (buffer, 1000, stdin);
I am writing a program for fun (not for school), and am having a hard time figuring out why the scanf function isn't executing on every iteration of my loop - I've toyed with both 'for' loops and 'while' loops.
I know that depending on how I write the scanf function (i.e. scanf("%s", &variablename); VS scanf("%99[^\n]s", &variablename);) makes a difference, but I have tried everything and I'm desperate!
When I do a printf check on my input from the scanf, on every iteration it is only intaking one string per iteration, so if I enter two words in my first input, then it takes two iterations to process - one word per. Here is the segment of code I'm describing:
int main(void){
int tries = 0;
int score = 0;
char question[100];
char useranswer[100];
const char *phrase = {"our favorite saying\0"};
printf("\nQuestion #3 (10 points): What is our secret saying?\n");
sleep(1);
tries = 1;
while (tries<=3){
printf("YOUR ANSWER:");
scanf("%s[^\n]", useranswer);
if(strncmp(useranswer, phrase, 15) != 0){
printf ("Nope, try again!\n");
printf("You have used %d out of 3 tries!\n", tries);
if (tries == 2){
printf("Here's your final hint:xxx...\n");
}
if (tries == 3){
printf("You didn't get it. The answer is: our favorite saying!\n");
}
tries++;
}
if (strncmp(useranswer, phrase, 15) == 0){
printf("Damn, you're good. Well done.\n");
score += 10;
break;
}
}
The output of this code is:
Question #3 (10 points): What is our secret saying?
YOUR ANSWER:our favorite saying
Nope, try again!
You have used 1 out of 3 tries!
YOUR ANSWER:Nope, try again!
You have used 2 out of 3 tries!
Here's your final hint:xxx...
YOUR ANSWER:Nope, try again!
You have used 3 out of 3 tries!
You didn't get it. The answer is: our favorite saying!
(It only allowed me to input once, and I typed "our favorite saying".)
In comments you could find why your format specifier in scanf doesn't work.
An alternative is to use fgets instead, maybe in an helper function which takes care of some of the corner cases that can arise while reading user input:
#include <ctype.h>
char *read_line( char *buf, size_t n, FILE *pfin )
{
ssize_t length = 0;
int ch;
if ( !buf || n == 0 )
return NULL;
/* Consume trailing control characters, like '\0','\n', '\r', '\f'...
but also '\t'. Note that ' ' is not skipped. */
while ( (ch = fgetc(pfin)) != EOF && iscntrl(ch) ) { }
if ( ch == EOF )
return NULL;
/* At least one char is printable */
*buf = ch;
++length;
/* Read from file till a newline or up to n-2 chars. The remaining chars
are left in the stream buffer. Return NULL if no char is read. */
if ( fgets(buf + 1, n - 1, pfin) )
{
/* Trim the string to the first control character */
while ( !iscntrl(buf[length]) )
{
++length;
}
buf[length] = '\0';
}
return buf;
}
I'd change the following logic too. OP uses strncmp(useranswer, phrase, 15) multiple times, but that magic number 15 is lower then phrase's size so it ends up comparing only a substring.
while ( tries <= 3 ) {
printf("YOUR ANSWER:");
if ( !read_line(useranswer, sizeof useranswer, stdin) ) {
printf("Error: Unexpected end of input.\n");
exit(EXIT_FAILURE);
}
if( strcmp(useranswer, phrase) == 0 ) {
printf("Damn, you're good. Well done.\n");
score += 10;
break;
} else {
printf ("Nope, try again!\n");
printf("You have used %d out of 3 tries!\n", tries);
if (tries == 2) {
printf("Here's your final hint:xxx...\n");
}
if (tries == 3) {
printf("You didn't get it. The answer is: our favorite saying!\n");
}
tries++;
}
}
As a final note, I found OP declaration of phrase a bit weird (maybe a typo):
const char *phrase = {"our favorite saying\0"};
// string literals are already ^^ null terminated...
While we can use a simple array declaration, like:
const char phrase[] = "our favorite saying";
Consider also what values sizeof phrase returns in those two different cases.
Thanks to #chux for all the valuable hints and the interesting links provided:
https://stackoverflow.com/a/27729970/4944425
https://stackoverflow.com/a/28462221/4944425
And to #Dmitri for having pointed out in his comment that once we are sure that both the strings are null terminated, we can use strcmp instead of strncmp.
I need to analyze a string previous reader with fgets,
then I have a row from:
name age steps\n
mario 10 1 2 3 4\n
joe 15 3 5\n
max 20 9 3 2 4 5\n
there are a variable number of steps for each column,
then I can read name and age with
sscanf(mystring, "%s %d", name, &age);
after this I have a for cycle for read all steps
int step[20];
int index=0;
while(sscanf(mystring,"%d", &step[index++])>0);
but this cycle never ends populating all array data with the age column.
The reason this never ends is because you are constantly providing the same string to scan.
sscanf provides the %n switch which stores the amount of characters read before it is reached inside a, which allows you to move forward in your input string by that amount of characters before rescanning.
This'll work:
int step[20];
int index=0;
int readLen;
while(sscanf(mystring,"%d%n", &step[index++], &readLen)>0) {
mystring += readLen;
}
A working solution is given in the answer from sokkyoku.
Another possibility to read variable length lines is to use strtok like in the following code snippet:
int getlines (FILE *fin)
{
int nlines = 0;
int count = 0;
char line[BUFFSIZE]={0};
char *p;
if(NULL == fgets(buff, BUFFSIZE, fin))
return -1;
while(fgets(line, BUFFSIZE, fin) != NULL) {
//Remove the '\n' or '\r' character
line[strcspn(line, "\r\n")] = 0;
count = 0;
printf("line[%d] = %s\n", nlines, line);
for(p = line; (p = strtok(p, " \t")) != NULL; p = NULL) {
printf("%s ", p);
++count;
}
printf("\n\n");
++nlines;
}
return nlines;
}
Explanation of the above function getlines:
Each line in the file fin is read using fgets and stored in the variable line.
Then each substring in line (separated by a white space or \t character) is extracted and the pointer to that substring stored in p, by means of the function strtok in the for loop (see for example this post for further example on strtok).
The function then just print p but you can do everything with the substring here.
I also count (++count) the number of items found in each line. At the end, the function getline count and returns the number of lines read.
I have to compare 2 strings, one from a file, and one from a user input, here is the file:
Password
abcdefg
Star_wars
jedi
Weapon
Planet
long
nail
car
fast
cover
machine
My_little
Alone
Love
Ghast
The code for getting the string from the line is fine but the code for comparing the 2 strings does not give the right output
int main(void){
int loop, line;
char str[512];
char string[512];
FILE *fd = fopen("Student Passwords.txt", "r");
if (fd == NULL) {
printf("Failed to open file\n");
return -1;
}
printf("Enter the string: ");
scanf("%s",string);
printf("Enter the line number to read : ");
scanf("%d", &line);
for(loop = 0;loop<line;++loop){
fgets(str, sizeof(str), fd);
}
printf("\nLine %d: %s\n", line, str);
if(strcmp(string,str) == 0 ){
printf("Match");
}else{
printf("No Match");
}
fclose(fd);
getch();
return 0;
}
Perhaps the str resets but i don't know, perhaps some of the talented programmers here can see the problem.
Anyone know what is wrong with my string comparison?
Correct output:
Input: jedi, 4 Output: Match
edit: Both strings are the same, in the same case
edit: dreamlax fixed this.
fgets() does not discard any newline character after reading, so it will be part of str, which will cause the comparison to fail since string won't have a newline character. To get around this, you simply need to remove the newline character from str.
str[strlen(str) - 1] = '\0';
if (strcmp(string, str) == 0)
// ...
Ideally, make sure strlen(str) > 0 first, otherwise you will invoke undefined behaviour.
Hi guys I have this file struct:
0
2 4
0: 1(ab) 5(b)
1: 2(b) 6(a)
2: 0(a) 2(b)
3: 2(a) 6(b)
4: 5(ab)
5: 2(a) 6(b)
6: 4(b) 6(ab)
Each line will feed a struct with its data (numbers + letters).
What's the best way to read the line and get the strings I want?
Example:
0
2 4
0,1,ab,5,b
1,2,b,5,a
...
The lines may vary in size because we can have 1, 2, 3, .... numbers.
I already did it :
//struct
#define MAX_ 20
struct otherstats{ //struct otherStats
int conectstat[MAX_];//conection with others stats
int transitions[MAX_];//Symbols betwen conection ASCI
}tableStats[MAX_];
struct sAutomate{
int stat_initial; //initial
int stats_finals[MAX_]; //final orfinals
struct otherstats tableStats[MAX_]; //otherStats 0 1 2 3 4 5 6
};
/* eXample that what i want ..using the example
sAutomate.stat_initial=0
sAutomate.stats_finals[0]=2
sAutomate.stats_finals[1]=4
Others Stats table
//0
sAutomate.tableStats[0].conectstat[0]=1;
sAutomate.tableStats[0].conectstat[1]=5;
sAutomate.tableStats[0].transitions[0]=ab;
sAutomate.tableStats[0].transitions[1]=b;
//1
sAutomate.tableStats[1].conectstat[0]=2;
sAutomate.tableStats[1].conectstat[1]=6;
sAutomate.tableStats[1].transitions[0]=b;
sAutomate.tableStats[1].transitions[1]=a;
///etc
*/
void scanfile(){ //function to read the file
struct sAutomate st; //initialize st struct
char filename[] = "txe.txt";
FILE *file = fopen ( filename, "r" );
char buf[81];
char parts[5][11];
fscanf(file,"%d", &st.stat_initial);//read first line
printf("initial state : %d \n", st.stat_initial);
fscanf(file,"%d",&st.stats_finals);
fscanf(file,"%d",&st.stats_finals);
while (fgets(buf, sizeof(buf), stdin) != NULL)
{
if (sscanf(buf, "%10[^:]: (%10[^(], %10[^)]), (%10[^(], %10[^)])",
parts[0], parts[1], parts[2], parts[3], parts[4]) == 5)
{
printf("parts: %s, %s, %s, %s, %s\n",
parts[0], parts[1], parts[2], parts[3], parts[4]);
}
else
{
printf("Invalid input: %s", buf);
}
}
//fclose
First problem I see is you're overwriting stats_finals:
fscanf(file,"%d",&st.stats_finals);
fscanf(file,"%d",&st.stats_finals);
What you wanted to do here was:
fscanf(file,"%d",&st.stats_finals[0]);
fscanf(file,"%d",&st.stats_finals[1]);
To save off both the "2" and the "4" from the text file.
Second major problem is you're reading from stdin:
while (fgets(buf, sizeof(buf), stdin) != NULL)
That doesn't read your text file, that reads input from the keyboard... So you wanted that to be:
while (fgets(buf, sizeof(buf), file) != NULL)
Third (minor) problem is that fscanf() will not read newlines, and fgets() will. This means when you go from reading your second stats_finals to the first read in the while loop, your first input will just be the left over newline character. That's not a big deal since you check for "invalid input", but it's worth noting.
Finally, your sscanf looks wrong to me:
sscanf(buf, "%10[^:]: (%10[^(], %10[^)]), (%10[^(], %10[^)])",
^ ^
That's a width of 10, Why are you checking for commas? You didn't
I don't think that's have any in your text file
what you wanted...
I think this is more what you were looking for:
sscanf(buf, "%[0-9]: %[0-9](%[^)]) %[0-9](%[^)])",
^
takes a digit (0 to 9)
EDIT
Missed your original point. If you don't know how long the strings will be that you're reading, you can't use sscanf(). It's that simple. :)
The scanf family assumes you know how many objects you'll be parsing and the format string takes in that many. There are other options however.
Read a single line with fgets as you're doing, but then you can tokenize it. Either with the C function strtok or by your own hand with a for loop.
One note however:
Since you don't know how long it is, this: char parts[5][11]; is not your best bet. This limits you to 2 entries... probably it would be better to do this dynamically (read the line then allocate the correct size to store your tokens in.)
If you really don't know how many numbers and letters the line will contain, why are you reading a fixed amount of numbers and letters?
You could read the whole line with fgets and then parse it with a tokenizer like strtok, something like this:
const char* const DELIMITERS = " ";
int i; // index for tableStats
char* token;
token = strtok(line, DELIMITERS);
// first integer
if (token == NULL || sscanf(token, "%d:", &i) < 1)
// error
/* it seems like you should have at least one element in your "list",
* otherwise this is not necessary
*/
token = strtok(NULL, DELIMITERS);
if (token == NULL || sscanf(token, "%d(%[^)])",
&(tableStats[i].connectstat[0]),
&(tableStats[i].transitions[0])) < 2)
// error
// read optional part
for (int j = 1; (token = strtok(NULL, DELIMITERS)) != NULL; ++j)
if (sscanf(token, "%d(%[^)])", &(tableStats[i].connectstat[j]),
&(tableStats[i].transitions[j])) < 3)
break;
Remember that strtok changes the string, make a copy of it if you still need it.
Obviusly the code is for the arbitrary long lines, reading the first two lines is trivial.