Reading in text file in C - c

I've got a text file as follows:
sf5 sd6 sh7
or sh7 sd6 sf5 (any order of the two or the other possible 27 combinations).
I'm trying to extract the values 5,6, and 7 from it
However, I want to do this in any order possible, so sf(somenumber) can be in any of those 3 positions, as well as the other two. Thus, I'm trying to use strstr as one of my macros.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct test
{
char * values;
}test;
int main(int argc, char * argv[])
{
test t;
FILE * file;
char str[100];
int a,b,c;
if(argc > 1)
{
file = fopen(argv[1],"r");
if(file == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
while(fgets(str,100,file) != NULL)
{
t.values = strtok(str," \n");
if(t.values == NULL)
exit(1);
if(strstr(t.values,"sf"))
{
a = atol(t.values+2); // the number two positions after the letter
}
if(strstr(t.values,"sd"))
{
b = atol(t.values+2); // the number two positions after the letter
}
if(strstr(t.values,"sh"))
{
c = atol(t.values+2); // the number two positions after the letter
}
printf("Value of a: %d\n Value of b: %d\n Value of c: %d\n",a,b,c);
}
}
However the output is only correct for the first value "sf5", as if the second two aren't being parsed. Also, if I move "sf5" to the end, it's value provides to be zero which again makes no sense.
Basically, only the first if statement ever works successfully. Any help would be much appreciated!

The strstr function gives the position of the searched string or NULL if it's not found. You have to use this result in the atol function in order to get the value associated.
In the code below I use the variable tokento store the result of strstr:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char * argv[])
{
FILE * file;
char str[100];
int a,b,c;
if(argc > 1)
{
file = fopen(argv[1],"r");
if(file == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
while(fgets(str,100,file) != NULL)
{
char *token;
token = strstr(str,"sf"));
if (token != NULL)
{
a = atol(token+2); // the number two positions after the letter
}
token = strstr(str,"sd"));
if (token != NULL)
{
b = atol(token+2); // the number two positions after the letter
}
token = strstr(str,"sh"));
if (token != NULL)
{
c = atol(token+2); // the number two positions after the letter
}
printf("Value of a: %d\n Value of b: %d\n Value of c: %d\n",a,b,c);
}
fclose(file);
}

It may be helpful to print the value of t.values before each if block.
It shows that t.values does not change. Only the first if block's expression will be true.
If you want to do this using strtok...
"Subsequent calls with a null pointer for str1 will cause the previous position saved to be restored and begins searching from that point..."
So maybe insert calls of strtok(NULL, " \n"), like this:
t.values = strtok(str," \n");
if(strstr(t.values,"sf"))
{
a = atol(t.values+2); // the number two positions after the letter
}
t.values = strtok(NULL," \n"); // get pointer to next token
if(strstr(t.values,"sd"))
{
b = atol(t.values+2); // the number two positions after the letter
}
t.values = strtok(NULL," \n"); // get pointer to next token
if(strstr(t.values,"sh"))
{
c = atol(t.values+2); // the number two positions after the letter
}
printf("Value of a: %d\n Value of b: %d\n Value of c: %d\n",a,b,c);
Now the output is
Value of a: 5
Value of b: 6
Value of c: 7

Your code has two issues :
in the use of strstr() you don't use the return pointer, so that if encountering the string but not at the beginning, it vwill look for the digit at the wrong place;
you don't loop on strtok() to find the subsequent substrings. As strtok() cuts the string in pieces, you won't find anythning beyond the first separator with strstr();
Here an alternative solution based on your original approach (but as I'm very slow in typing, in the meanttime there are already 2 other valuable solutions ;-) )
while (fgets(str, 100, file) != NULL)
{
t.values = strtok(str, " \t\n");
while (t.values) { // loop to analyse each substring
if (p = strstr(t.values, "sf"))
a = atol(p + 2); // the number two positions after the FOUND string
else if (p = strstr(t.values, "sd"))
b = atol(p + 2); // the number two positions after the letter
else if (p = strstr(t.values, "sh"))
c = atol(p + 2); // the number two positions after the letter
t.values = strtok(NULL, " \t\n");
}
printf("Value of a: %d\n Value of b: %d\n Value of c: %d\n", a, b, c);
}
Now if you enter aaasf5 he will find 5 for a, while it found 0 before.
This code (nor yours) address the case where one of the value isn't found. You should therefore initialize your a,b,c to a defautlt value, for example 0.

Related

Finding first string in second string without pointers in C

I'm a newbie C language student.
My teacher said that we must write a project to:
Find second string in first string with no any pointer(*). Till now I've learned Loops, Conditions, Functions and Arrays and they are my lone options.
This project must get strings from user in two levels. Check them and print result.
For now I've written something bullshit:
int main()
{
char source[MAX_STR_LEN];
char target[MAX_STR_LEN];
int len = 50;
int a;
scanf("%s", &source);
scanf("%s", &target);
for (int i = 0; i <= len; i++)
{
if (strncasecmp(source[i], target[i], strlen(target)) == 0)
{
int a = 1;
if (a == 1)
{
printf("%s is inner of %s", target, source);
}
else
{
printf("%s is NOT inner of %s", target, source);
}
}
}
return 0;
}
but my project prints nothing and closes automatically when I enter two strings. I'm sure my code is not true is there any simple way to do it?
Thanks
First of all you have to improve the logic of how to search the substring in original string or if it is allowed by your teacher you can leave C language to search for it.
strstr doing that job.
Below is my code, i have add comment at your code
#include <stdio.h>
#include <strings.h>
#define MAX_STR_LEN 50
int main(void)
{
char source[MAX_STR_LEN];
char target[MAX_STR_LEN];
//int len = 50;
//int a;
scanf(" %s", source); //char array name is used like pointer to the first element of array
scanf(" %s", target);
char* ret = NULL;
ret = strstr(source, target);
if(ret == NULL)
printf("%s is NOT inner of %s", target, source);
else
printf("%s is inner of %s", target, source);
return 0;
}
A very simple approach is simply to check the source string character by character to see if the target string is found. In other words:
check if the target string is present starting at source[0].
if not: check if the target string is present starting at source[1].
if not: check if the target string is present starting at source[2].
and so on until you reach the end of the source string.
This can be done using two for-loops where the outer loop iterates all characters in the source string and the inner loop iterates the target string while comparing characters in the two strings.
You can visualize it like:
source: Hello World
target: lo
Hello World
lo // No match: He != lo
Hello World
lo // No match: el != lo
Hello World
lo // No match: ll != lo
Hello World
lo // Match: lo != lo
A simple implementation could look like:
int main()
{
char source[MAX_STR_LEN] = "Hello World";
char target[MAX_STR_LEN] = "lo";
int source_index = 0;
int match = 0;
while (source[source_index] != '\0')
{
int target_index = 0;
while (target[target_index] != '\0' &&
source[source_index + target_index] != '\0' &&
source[source_index + target_index] == target[target_index])
{
++target_index;
if (target[target_index] == '\0')
{
match = 1;
break;
}
}
if (match) break;
++ source_index;
}
if (match)
{
printf("found\n");
}
else
{
printf("not found\n");
}
return 0;
}
Brother you assign a value ofint a = 1;and right after you checkif(a == 1)which makes no sence becauseelse{printf("%s is NOT inner of %s", target, source);}this above part of code will never use in this scenario this is the solution https://www.geeksforgeeks.org/given-two-strings-find-first-string-subsequence-second/be carefull :)

Parsing a string with scanf

I need to get integers from a string that an user enters into the console.
For exemple:
I have this string: [1, 2, 3, 4, 5] and I would like to get all of the integers from it. I already tried multiple scanf patterns, such as scanf("%*[^\[]%d,", &a), but nothing worked. I couldn't find anything relevant on Stack Overflow either.
The main problem is that he can enters between 1 and 50 integers into his string. I have no idea about how to stock only integers (removing ',' and '[' ']' ) into an array.
Some solutions have been found for removing special chars such as [ ] or ,
But now I still need to remove SPACE between comas and integers...
EDIT : problem solved using fgets. I was using scanf to get my string, but it were stopping to SPACES.
Fond out how to do that with scanf :
while(scanf(" %d",&i))
scanf/sscanf does not support regular expressions. You should try something like:
const char my_string[] = "[1,2,3,4,5]";
int a,b,c,d,e;
sscanf(my_string, "[%d,%d,%d,%d,%d]", &a, &b, &c, &d, &e);
Example: http://ideone.com/AOaD7x
It can also be good to check the return value of scanf/sscanf:
int retval = sscanf(my_string, "[%d,%d,%d,%d,%d]", &a, &b, &c, &d, &e);
if (retval != 5)
fprintf(stderr, "could not parse all integers\n");
Reference
Edit:
In your edited question you asks how to do this if there is a variable number of integers. You can use strchr to locate the next comma in the string and continue to iterate until no more comma is found. This assumes that the string ends with ].
const char my_string[] = "[1,2,3,4,5]";
/* start at first integer */
const char *curr = &my_string[1];
while (curr != NULL) {
/* scan and print the integer at curr */
int tmp;
sscanf(curr, "%d", &tmp);
printf("%d\n", tmp);
/* find next comma */
curr = strchr(curr, ',');
/* if a comma was found, go to next integer */
if (curr)
/* warning: this assumes that the string ends with ']' */
curr += 1;
}
Example: http://ideone.com/RZkjWN
Try this piece of code, by using strtok you can separate out all type of unwanted characters in your string. Add all your unwanted set of character to this s array and let strtok do the work.
char str[]="[1,2,3,4,5]";
const char s[4] = "[],"; // All unwanted characters to be filtered out
char *token;
token = strtok(str, s);
while( token != NULL )
{
printf( "%d\n", atoi(token));
token = strtok(NULL, s);
}
Since you have it in the integer format, you could store it in an array and go further with it.
Output :
1
2
3
4
5
Using scanf() for parsing strings is not recommended.
Similarly to others answers, you can use strtok to parse the numbers between "[],", and convert the found numbers using strtol. It would be dangerous to use something like atoi() for integer conversion, as their is no error checking with it. Some more error checking with strtol() can be found in the man page.
Here is some sample(can be improved) code which does this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 50
#define BASE 10
int main(void) {
char string[] = "[1,2,3,4,5]";
char *number, *endptr;
const char *delim = "[],";
int numbers[MAXNUM], current;
size_t i, count = 0;
number = strtok(string, delim);
while (number != NULL) {
current = strtol(number, &endptr, BASE);
/* checking if valid digit found */
/* more error checking can be added */
if (endptr != number) {
numbers[count++] = current;
}
number = strtok(NULL, delim);
}
for (i = 0; i < count; i++) {
printf("numbers[%zu] = %d\n", i, numbers[i]);
}
return 0;
}
Sample input 1:
string[] = "[1,2,3,4,5]";
Output 1:
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
Sample input 2:
string[] = "[1,a,3,c,5]";
Output 2:
numbers[0] = 1
numbers[1] = 3
numbers[2] = 5

reading from different files and using strtok on strings

so this is a code that reads 3 strings (orig // test1 // orig_copy) from 2 different files (firstline // secondline)**and calls divide_string to use strtok and take tokens and store them in **(token_orig // token_test // token_orig_copy),
--> this is the problem :
- when i put the three lines in main it does compile and take token from all 3 strings and "Done ." in the end.
-but when i try the next three lines (notice how i changed "HAHAHAH" to "HAHAHAHA", that little changing changes everything and make the program stops at printf("for the string number two :"); .
i hope i cleared the problem
PS : you can past copy the program so you can compile yourself easily
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char s[4] = " ,.";
int divide_string(char* thestring,char** destination)
{
int i=0;
char* token=strtok(thestring,s);
destination[i]=malloc(sizeof(token)+1);
strcpy(destination[i],token);
i++;
printf("the word %d is 'tokened' \n",i);
while(token!=NULL)
{
token =strtok(NULL,s);
if (token != NULL)
{
destination[i]=malloc(sizeof(token)+1);
strcpy(destination[i],token);
printf("the word %d is 'tokened' \n",i);
++i;
}
}
return i;
}
void main ()
{ //TRY THESE THREE LINES THAT WORKS<-----------------------------
char orig[]= "does work HAHAHAH";
char orig_copy[] = "does work HAHAHAH";
char test1[]="does work HAHAHAH";
// char orig[]= "doesnt work HAHAHAHA";
// char orig_copy[] = "doesnt work HAHAHAHA";
// char test1[]="doesnt work HAHAHAHA";
char *token_orig[81];
char *token_test[81];
char *token_orig_copy[81];
strcpy(orig_copy,orig);
printf("for string number one : \n");
int max_orig = divide_string(orig,token_orig);
printf("for string number two : \n");
int a = divide_string(orig_copy,token_orig_copy);
printf("for string number three : \n");
int max_test = divide_string(test1,token_test);
printf("%s-",token_orig[0]);
printf("%s-",token_orig[1]);
printf("%s-\n",token_orig[2]);
printf("%s-",token_orig_copy[0]);
printf("%s-",token_orig_copy[1]);
printf("%s-\n",token_orig_copy[2]);
printf("%s-",token_test[0]);
printf("%s-",token_test[1]);
printf("%s-\n",token_test[2]);
printf("done .");
return 0;
}
Since token is a pointer, sizeof(token) gives you the size of the pointer variable (4 or 8 bytes probably), NOT the number of chars in the string it points to! You want:
strlen(token) + 1
instead (+1 for the \0).
About the only time sizeof is useful for character strings is literals like:
sizeof("Hello World")

Storing values of file into array leads to weird behaviour

Let's say I've got the file
5f2
3f6
2f1
And the code:(The printf should print the second numbers (i.e 2,6, and 1) but it doesn't
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, char * argv[])
{
FILE *ptr;
char str[100];
char * token;
int a, b, i;
int arr[4];
if(argc > 1)
{
ptr = fopen(argv[1],"r");
if(ptr == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
//And I'm looking to parse the numbers between the "f" so..
while(fgets(str,100,ptr) != NULL)
{
token = strstr(str,"f");
if(token != NULL)
{
a = atol(str); // first number
b = atol(token+1); // second number
arr[i] = b; // store each b value (3 of em) into this array
}
i++;
printf("Values are %d\n",arr[i]); //should print 2,6 and 1
}
}
I've tried to move the printf outside the loop, but that seems to print an even weirder result, I've seen posts about storing integers from a file into an array before, however since this involves using strstr, I'm not exactly sure the procedure is the same.
int i,j=0;
while(fgets(str,sizeof(str),file) != NULL)
{
size_t n = strlen(str);
if(n>0 && str[n-1] == '\n')
str[n-1] = '\0';
i = str[strlen(str)-1] - '0'; /* Convert the character to int */
printf("%d\n",i);// Or save it to your int array arr[j++] = i;
}
Just move to the last character as shown and print it out as integer.
PS: fgets() comes with a newline character you need to suppress it as shown
You are never initializing i, then you are reading into arr[i] (which just happens to not crash right there), then increment i (to "undefined value + 1"), then print arr[i] -- i.e., you are writing to and reading from uninitialized memory.
Besides, your FILE * is ptr, not file. And you should get into the habit of using strtol() instead of atol(), because the former allows you to properly check for success (and recover from error).

Using fscanf in C

I am trying to read from a file into array.
My file called Players.txt contains:
Del Piero|3|Italy|Juventus|
Ronaldo|0|Portugal|Real Madrit
I used fscanf , but it is not working correctly , I am not doing right the conversion.
can anyone help me to read and store them into arrays. Like the array player name to contain { Del Piero, Ronaldo}
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#define NUM_PLAYERS 20
#define NAME_LENGTH 100
#define COUNTRY_NAME 20
int main (void)
{
FILE *Players;
char player_name [NUM_PLAYERS][NAME_LENGTH] = {0};
char country_name[NUM_PLAYERS][COUNTRY_NAME] = {0};
char team_name[NUM_PLAYERS][NAME_LENGTH] = {0};
int goals_scored[NUM_PLAYERS] = {0};
int i;
Players = fopen("G:\\COP2220\\Project 5\\Players.txt", "r");
if (Players == NULL)
{
printf("File not found.\n");
}
else
{
while (fscanf(Players, " %[^|]s %[^|]d %[^|]s %[^|]s",player_name[i],&goals_scored[i],country_name[i],team_name[i]))
{
printf("The player %s, scored %d from %s plays in %s\n", player_name, goals_scored,country_name, team_name );
}
}
fclose(Players);
return 0;
}
[] is a type all in itself, you shouldn't append s or d at the its end. All you really have to do is change the format to this:
"%[^|] | %d | %[^|] | %[^|]|\n"
And consider changing your while loop to break when fscanf doesn't return 4.
Here's some working code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#define NUM_PLAYERS 20
#define NAME_LENGTH 100
#define COUNTRY_NAME 20
int
main (void)
{
FILE * Players;
char player_name [NUM_PLAYERS][NAME_LENGTH] = {0};
char country_name[NUM_PLAYERS][COUNTRY_NAME] = {0};
char team_name[NUM_PLAYERS][NAME_LENGTH] = {0};
int goals_scored[NUM_PLAYERS] = {0};
int i = 0, ret = 0;
Players = fopen("testfile", "r");
if (Players == NULL)
{
printf("File not found.\n");
}
else
{
for (;;)
{
ret = fscanf(Players, "%[^|] | %d | %[^|] | %[^|]|\n",
player_name[i],
&goals_scored[i],
country_name[i],
team_name[i]);
if (ret != 4)
{
printf ("only %d arguments were matched\n", ret);
break;
}
printf("The player %s, scored %d from %s plays in %s\n",
player_name[i],
goals_scored[i],
country_name[i],
team_name[i]);
i++;
}
fclose(Players);
}
return 0;
}
The scanf format %[^|]s reads a string of non-| characters followed by an s character, which can never match (since the next character after the string, if it exists, must be a |, not an s). You probably want something more like:
while (4 == fscanf(Players, " %99[^|\n]|%d| %19[^|\n]| %99[^|\n]", player_name[i], &goals_scored[i], country_name[i], team_name[i]))
Note the additional string size limits to avoid overflowing arrays, and the newlines in the patterns, so that they can't be included in any of the strings (but can appear between strings).
Note also that this will match your second line, but will leave |Madrit to be read by the next call to fscanf, so you might want to put
fscanf(Players, "%*[\n]%*c");
in the loop to read the rest of the line up to the newline and throw it away.
You never actually consume the "|" characters in between your fields. Instead you're only reading up until the "|" character. Try adjusting your format string to something like:
"%[^|]|%[^|]d|%[^|]|%[^|]"
Your format scan string is incorrect. The %[..] is itself the format specifier, adding the s or d after it is just taken to be a literal s or d in the scan string, and not a %s or %d like you are expecting.
Also, your printf() prints out the goals_scored address rather than the stored value for the player. You forgot to index the array.
It is possible to get your format scan string to work, but since the last field appears optional, you have some complexity to deal with that case. In the code below, we deal with this by explicitly calling out that the newline should not be part of the last field. Then the %*c will discard either the | or the \n at the end. The space at the end of the scan string allows fscanf() to move to the next line in the case that the | was discarded.
while (fscanf(Players, " %[^|]|%d|%[^|]|%[^|\n]%*c ",
player_name[i], &goals_scored[i], country_name[i], team_name[i]) == 4)
{
printf("The player %s, scored %d from %s plays in %s\n",
player_name, goals_scored[i], country_name, team_name);
}
However, this problem seems ideal for strtok(). The advantage is that you have more control over how to deal with each field, and you can get more information about where errors are occurring during a parse of the line.
int parse_line (char *buffer,
char *name, int *goals, char *country, char *team,
char **rest)
{
char *tok = strtok(buffer, "|");
int count = 0;
while (tok && count < 4) {
++count;
switch (count) {
case 1: strcpy(name, tok); break;
case 2: *goals = atoi(tok); break;
case 3: strcpy(country, tok); break;
case 4: strcpy(team, tok); break;
default: break;
}
tok = strtok(0, "|");
}
*rest = tok;
return count;
}
You would change your code to read in a line of data, and then feed that line to the parse_line() function.
char buf[MAX_LINE_LENGTH];
char *rest;
while (fgets(buf, sizeof(buf), Players) != 0) {
parse_line(buf,
player_name[i], &goals_scored[i], country_name[i], team_name[i],
&rest);
printf("The player %s, scored %d from %s plays in %s\n",
player_name, goals_scored[i], country_name, team_name);
}

Resources