#include <stdio.h>
#include <ctype.h>
int main(void)
{
const char *str = NULL;
size_t len = 0;
getline(&str,&len,stdin);
int i = 0;
unsigned int count = 0, tmp = 0;
printf("%s\n", str);
while (sscanf(&str[count], "%d %n", &i, &tmp) != EOF) {
count += tmp;
printf("number %d\n", i);
}
return 0;
}
What I'm trying to do here is ask the user for a line of integers (positive or negative) and I only care about integers that are valid that have a space between them, if there was a non numeric char entered then it should ignore what comes after it. Up top is what I have so far but I have some bugs with it, what I have right now is also ignoring white space which is what I want. Look at EXP for more clarification.
EXP:
input: 1 2 3 4a desired output-> 1 2 3 my ouput-> 1 2 3 4 4
input: 1 2 3 a4 desired output-> 1 2 3 my ouput-> 1 2 3 3
input: 1 2 3 a b c 4 5 6 7 desired output-> 1 2 3 my output-> 1 2 3 3 3 3 4 5 6 7
Valid input EXP:
input: 12 367 98 -3 -67 desired output-> 12 367 98 -3 -67
Whenever you need to work through a buffer picking out numeric values, you want to think strtoX() (where X can be l, ul, f, d, for strtol(), etc..) The reason being is two-fold. (1) these functions were designed to allow you to do that by providing parameters of a pointer to the string itself, and the endptr parameter that is updated to point to the next character after the last digit successfully converted; and (2) these function provide complete error detection for all aspects of the conversion.
By virtue of the endptr parameter being updated to one-past the last digit converted, you simply loop through your buffer, attempting the conversion, and upon successfully conversion, you just update the the initial pointer to endptr and repeat until you run out of characters. See man 3 strtol
Since endptr is updated to point one-past the last digit converted, you can simply check whether the character pointed to be endptr is either the nul-terminating character for the string or !isspace(*endptr) to determine if a non-digit was included in that group of numbers.
A simple implementation for your case would be:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
char *p = buf, *ep = p; /* pointers to use with strtol() */
for (;;) { /* loop continually */
errno = 0; /* reset errno */
long val = strtol (p, &ep, 0); /* attempt conversion to long */
if (p == ep) /* check if no characters converted */
break;
else if (errno) /* check for under/overflow */
break;
else if (*ep && !isspace(*ep)) /* check next char for non-space */
break;
else
printf (" %ld", val); /* good all-digit conversion */
p = ep; /* update pointer to endpointer */
}
putchar ('\n'); /* tidy up with newline */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Example Input File
$ cat dat/numwalpha.txt
1 2 3 4a
1 2 3 a4
1 2 3 a b c 4 5 6 7
Example Use/Output
$ ./bin/strtol_numonly dat/numwalpha.txt
1 2 3
1 2 3
1 2 3
Adding Error Reporting
On failure, you can simply output the characters beginning at endptr (ep above) to see why things failed. You can include a preprocessor directive to turn the error reporting on/off by using a DEBUG define if you like, e.g.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
char *p = buf, *ep = p; /* pointers to use with strtol() */
for (;;) { /* loop continually */
errno = 0; /* reset errno */
long val = strtol (p, &ep, 0); /* attempt conversion to long */
if (p == ep) { /* check if no characters converted */
#ifdef DEBUG
fprintf (stderr, "error: no digits converted in '%s'.\n", p);
#endif
break;
}
else if (errno) { /* check for under/overflow */
#ifdef DEBUG
fprintf (stderr, "error: over/under-flow in conversion or '%s'.\n", p);
#endif
break;
}
else if (*ep && !isspace(*ep)) { /* check next char for non-space */
#ifdef DEBUG
fprintf (stderr, "error: mixed alphanumeric '%s'.\n", ep);
#endif
break;
}
else
printf (" %ld", val); /* good all-digit conversion */
p = ep; /* update pointer to endpointer */
}
putchar ('\n'); /* tidy up with newline */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Then compiled with -DDEBUG to enable the define, you would have:
$ ./bin/strtol_numonly dat/numwalpha.txt
error: mixed alphanumeric 'a
'.
1 2 3
error: no digits converted in ' a4
'.
1 2 3
error: no digits converted in ' a b c 4 5 6 7
'.
1 2 3
Which shows the first case failed due to an 'a' at the end, the second due to an "a4" as the string to be converted, and the last because "a b c 4 5 6 7" was all that was left in the string, with 'a' being the next conversion.
Related
I want to read the stdin with fgets.
Then, I want to read each line. My lines are strings separated with ' '.
For example, this could be a line: 1 2 ab
I thought than I should use a malloc to count the number of params in my line because this number can vary from a line to another.
1 2 3 4 has 4 but a b 2 has 3.
I cut the line with strtok and then I fill my malloc with the tokens and I print them.
The final result is only to print each lines.
For example, this is a file.txt:
1 2 33 4
a b1 c
4 b l 11
And I do:
$ cat file.txt | ./a.out
It should print:
1 2 33 4
a b1 c
4 b l 11
but it doesn't!
Can you guys help me with this please :O
Furthermore, I want to use array to count the tokens and to work with them later. For example, I need to work separately with all the second param of each line, so array[1].
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv) {
while (fgets(argv, sizeof(argv), stdin) != NULL) {
char *array = (char *)malloc(sizeof(argv));
char *token = strtok(argv, " ");
strtok(token, "\n");
int i = 0;
while (token != NULL) {
array[i] = token;
token = strtok(NULL, " ");
printf("%d\n", array[i]);
++i;
}
}
return 0;
}
If all you want to do is count the tokens and output them, then you can simply use a pointer to the token and do not need to allocate storage. Using strtok() would be a good way to go. (note: if you have empty fields, you will need to parse using another method as strtok() will consider sequential delimiters as a single delimiter). The string passed to strtok() must be mutable as strtok() modifies the string (make a copy if you need to preserve the original)
Your approach is to read each line with fgets() into a sufficiently sized buffer (character array), zero your counter and then tokenize the line, incrementing the count for each token and output the token separated by a space.
You could do that as follows:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char line[MAXC]; /* storage for line */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (line, MAXC, fp)) {
size_t toks = 0,
len;
line[(len = strcspn (line, "\n"))] = 0; /* trim \n, save length */
for (char *p = strtok (line, " \t"); p; p = strtok (NULL, " \t"))
printf (toks++ ? " %s" : "%s", p);
printf ("%*s\t(%zu tokens)\n", (int)len % 8, " ", toks);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Above a ternary is used to control the output of the space-separator (nothing before the first token -- when the count is zero, and then a single space before each subsequent token). The count of the tokens is appended to the end of each line.
(the strlen() of each line is just used to tidy up the spacing between the end of each output line and the appended count by adding the fractional part of a tab, if needed)
Example Use/Output
With your example data in the file dat/tokfile.txt, you would receive:
$ ./bin/fgets_tok_count dat/tokfile.txt
1 2 33 4 (4 tokens)
a b1 c (3 tokens)
4 b l 11 (4 tokens)
By taking the filename as the first argument to the program, or reading from stdin by default if no argument is given, you can redirect information to your program as well, e.g.
$ ./bin/fgets_tok_count < dat/tokfile.txt
Or heaven forbid your UUOc form will also work:
$ cat dat/tokfile.txt | ./bin/fgets_tok_count
Dynamically Storing Unknown Number of Tokens Per-Line
To dynamically stored each token and preserve each for the duration of your tokenization loop, then all you need is a pointer-to-pointer-to char and a counter to track the number of pointers and strings allocated. You can do that similar to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char line[MAXC]; /* storage for line */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (line, MAXC, fp)) {
char **tokens = NULL;
size_t len = 0,
toks = 0;
line[(len = strcspn (line, "\n"))] = 0; /* trim \n, save length */
/* loop over each token */
for (char *p = strtok (line, " \t"); p; p = strtok (NULL, " \t")) {
size_t toklen = strlen (p);
/* allocate/validate 1 additional pointer for tokens */
void *tmp = realloc (tokens, (toks + 1) * sizeof *tokens);
if (!tmp) {
perror ("realloc-tokens");
break;
}
tokens = tmp;
/* allocate/validate storage for token of len + 1 */
if (!(tokens[toks] = malloc (toklen + 1))) {
perror ("malloc-tokens[toks]");
break;
}
/* copy token to allocated block */
memcpy (tokens[toks], p, toklen + 1);
toks++; /* increment no. of tokens in line */
}
/* output all stored line tokens and no. of tokens */
for (size_t i = 0; i < toks; i++) {
printf (i ? " %s" : "%s", tokens[i]);
free (tokens[i]); /* done with stored token, free token */
}
free (tokens); /* free pointers */
printf ("%*s\t(%zu tokens)\n", (int)len % 8, " ", toks);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
(the program output is the same)
Basically, above, realloc is used to allocate storage for 1-additional pointer each time a token is found, malloc is then used to allocate for the length of the token (+1), and then the token is copied to that allocated block. When you are done tokenizing the line, the tokens pointer points to a block of memory containing toks pointers, to which a block of memory holding each token was assigned in turn. After all tokenization and storage is complete, the same output is produced by looping over the pointers, outputting the tokens (and the number of tokens). All memory is then freed.
Look things over and let me know if you have further questions.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have a textfile with these following numbers and characters inside of it.
36#xL!?\8
28?>\4
42<pX%7
37##5
31kL%^?>\<#%5
Now, i want to get the first integer which is 36 and subtract it on the last integer which is 8. I want to do this line by line.
You want to read in the line, parse the numbers at the beginning and end, then convert them to integers. Here is a simple example:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
main()
{
FILE *file = fopen("input.txt", "r");
char line[256];
while (fgets(line, sizeof(line), file))
{
char num[15];
int firstNumber = 0;
int secondNumber = 0;
line[strcspn(line, "\r\n")] = 0;
for (int x = 0; x < 256; x++)
{
if (isdigit(line[x]))
{
num[x] = line[x];
}
else
{
num[x] = 0;
break;
}
}
firstNumber = atoi(num);
int length = strlen(line);
int ndx = 0;
while (length >=0 && isdigit(line[length - 1]))
{
num[ndx] = line[length - 1];
ndx++;
length--;
}
num[ndx] = 0;
secondNumber = atoi(num);
printf("%d - %d = %d\n", firstNumber, secondNumber, firstNumber - secondNumber);
}
fclose(file);
}
You already have a good answer for the file posted as part of your question, however, the result of first - last will be incorrect if you line of text contains a '-' sign before the digits indicating a negative signed value. All of the C string to integer conversions will accept a leading +/- before the value to be converted indicating a positive or negative number. If your input can contain negative values, you need to preserve the '-' sign by including that with the digits to be converted. For example if your input file was:
36#xL!?\-8
28?>\4
-42<pX%7
37##-5
31kL%^?>\<#%5
The answers would be quite different with -8, -42 and -5 as the integer values from the file. Now if that isn't a possibility based on your specific assignment, then you can skip preserving the '-', but for read-world text conversion to signed values, it is critical.
One way of finding the beginning of a signed number for conversion in a string is simply scan forward in the string (similar to what strpbrk() would do) looking for either a beginning digit or '-' (whichever occurs first). If the '-' occurs first, you then check that the next character is a digit. You can do it with a simple loop, e.g.
/** scan forward in 'p' to find beginning of next valid signed integer.
* returns pointer to beginning of signed int on success, NULL otherwise.
*/
const char *nextdigit (const char *p)
{
while (*p) {
/* if digit or +/- followed by a digit */
if (isdigit(*p) ||
((*p == '-' || *p == '+') && isdigit(*(p + 1))))
return p;
p++;
}
return NULL;
}
Once you have found the beginning of a digit, then you need to use a function that provides error-checking on the conversion. atoi() provides zero diagnostics for the conversion and will silently return 0 as a valid number for the conversion of atoi("my cow"); You will have no indication whether digits were actually converted or whether the result exceeds the storage size for all integer types. atoi() issues no errors at all, even if provided with a 200 digit string as input. At minimum, use sscanf that will at least provide a yes/no, true/false as to whether a valid conversion took place, or better, use strtol which provides full error reporting on the conversion.
For example, you can write a short function that take the address of a pointer to string, use nextdigit() function above, and then use strtol to fully validate the result, setting errno for validation back in the caller on any error and returning the results of the integer conversion (or 0 on error) as follows:
/** returns next integer in string pointed to by p, or sets errno and returns
* zero on error.
*/
int getnextint (char **p)
{
int nextint = 0;
errno = 0;
if ((*p = (char*)nextdigit(*p))) {
char *endptr;
long tmp = strtol (*p, &endptr, 0);
if (*p == endptr) { /* validate digits converted */
fputs ("error: no digits converted.\n", stderr);
errno = EINVAL;
}
else if (errno) /* validate conversion */
fputs ("error: over/underflow occurred.\n", stderr);
/* validate tmp is in range of integer */
else if (INT_MIN <= tmp && tmp <= INT_MAX)
nextint = tmp;
else {
fputs ("error: value exceeds range of int.\n", stderr);
errno = ERANGE;
}
*p = (char*)nextdigit(endptr);
}
else
errno = EINVAL; /* if no digits found, set EINVAL */
return nextint;
}
(note: the address of the pointer is passed so that the pointer can be updated within the function to the beginning of the next integer to convert in the string (or NULL if no more remain)
To complete the example, you can add the needed headers and write a short main() to read from your filename provided as the first argument (or read from stdin by default if no argument is provided) that will locate the first and last integers in each line and subtract first - last outputting the result:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strcspn */
#include <limits.h> /* for INT_MIN/INT_MAX */
#include <errno.h> /* for errno */
#include <ctype.h> /* for isdigit */
#define ARSZ 100
#define MAXC 1024
... /* insert functions here */
int main (int argc, char **argv) {
char buf[MAXC] = "";
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line of input */
int arr[ARSZ] = {0};
char *p = buf;
size_t n = 0;
buf[strcspn(buf, "\r\n")] = 0;
while (n < ARSZ && p) {
arr[n] = getnextint (&p);
if (!errno)
n++;
}
if (n > 1)
printf ("%-19s : % 2d - % 2d = % 3d\n",
buf, *arr, arr[n-1], *arr - arr[n-1]);
else
fprintf (stderr, "%zu integer(s) in: '%s'\n", n, buf);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Example Input Files
Your original input file:
$ cat dat/last-first.txt
36#xL!?\8
28?>\4
42<pX%7
37##5
31kL%^?>\<#%5
And another with negative values and additional extraneous lines:
$ cat dat/last-first2.txt
36#xL!?\-8
28?>\4
-42<pX%7
Nothing to see!
37##-5
31kL%^?>\<#%5
Example Use/Output
$ ./bin/fgets_strtol_any_last-first dat/last-first.txt
36#xL!?\8 : 36 - 8 = 28
28?>\4 : 28 - 4 = 24
42<pX%7 : 42 - 7 = 35
37##5 : 37 - 5 = 32
31kL%^?>\<#%5 : 31 - 5 = 26
When run on the file with negative values and the extraneous line:
$ ./bin/fgets_strtol_any_last-first dat/last-first2.txt
36#xL!?\-8 : 36 - -8 = 44
28?>\4 : 28 - 4 = 24
-42<pX%7 : -42 - 7 = -49
0 integer(s) in: 'Nothing to see!'
37##-5 : 37 - -5 = 42
31kL%^?>\<#%5 : 31 - 5 = 26
As you can see from the result of the subtractions between the different files, it makes a great deal of difference whether you preserve the leading '-' when converting signed values. Something to consider going forward.
Look things over and let me know if you have additional questions.
I have a text file with one line with numbers separated by space as in the following example:
1 -2 3.1 0xf 0xcc
After parsing the file with a C program,the results should be saved in a vector and its internal structure should be:
V[0]=1
V[1]=-2
V[2]=3.1
V[3]=15
V[4]=204
Basically i need to convert the numbers that start with 0x into decimal numbers.
I have tried storing all elements in a char vector and then transform them in numbers but without much succes.
Any help with a piece of code in C will be greatly appreciated.Thanks
You could have a look at sscanf. Here's a bare-bones program. I am sure you can pick up from here:
#include <stdio.h>
int main(void)
{
char *hex = "0xF";
int i= 0;
sscanf(hex, "%x", &i);
printf("%d", i);
}
What you need is strtol function for integer types. You can use endptr to iterate through the string. For double you can use atof function, but you have to check firstly if the string contains a dot.
EDIT: As user3386109 mentioned strtod is a better solution for double.
Assuming that you have the string in an array:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char numbers_str[] = "1 -2 3.1 0xf 0xcc";
int ints[10];
double doubles[10];
int ints_idx = 0, doubles_idx = 0;
const char delims[] = " ";
char *it = strtok(numbers_str, delims);
while(it != NULL)
{
char *dot_it = strchr(it, '.');
// When a dot is found then a double number is found
if(dot_it)
doubles[doubles_idx++] = strtod(it, NULL);
// When a dot is not found then we've got an integer
else
ints[ints_idx++] = strtol(it, NULL, 0);
it = strtok(NULL, delims);
}
printf("Integers found: \n");
for(int i = 0; i < ints_idx; ++i)
printf("%d\n", ints[i]);
printf("Double numbers found: \n");
for(int i = 0; i < doubles_idx; ++i)
printf("%f\n", doubles[i]);
}
The easiest way to handle reading the values from the line is to work your way down the line with strtod. strtod takes two pointers as parameters. The first points to the beginning point to search for digits (or leading +/-) in order to convert the string representation of the number to a numeric value (all leading whitespace is skipped). The second pointer-to-pointer (endptr) will be set to the next character following the last character used in the conversion. You start your search for the next number to convert from there (e.g. set p = ep; and repeat the process).
You can consult the man page for further details, but to validate a successful conversion, you check that the pointer is not equal to the end-pointer (meaning digits were converted) and you check to make sure errno was not set. If there were no digits converted (meaning you had an invalid character), you simply want to scan forward in the line manually until your next +/- or 0-9 is found (or you hit the nul-terminating character).
You want to protect your array bounds and limit the number of values you try and store in your vector array by keeping a simple counter and exiting the loop when your array is full.
Here is a short example (NAN and INF checking omitted):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define VECSZ 5 /* if you need a constant, define one (or more) */
int main (int argc, char **argv) {
int i, n = 0;
double v[VECSZ] = {0.0};
char buf[BUFSIZ] = "";
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (n < VECSZ && fgets (buf, BUFSIZ, fp)) { /* read each line */
char *p = buf, *ep; /* pointer, end-pointer for strtod */
while (n < VECSZ) { /* convert vales in buf until VECSZ */
double tmp = strtod (p, &ep);
if (p != ep) { /* digits converted */
if (!errno) /* validate no error */
v[n++] = tmp; /* add to vector */
p = ep; /* update pointer */
}
else { /* no digits converted */
fprintf (stderr, "error: no digits converted.\n");
/* scan forward to next valid '+,-,0-9' */
while (*p && *p != '-' && *p != '+' && (*p < '1' || '9' < *p))
p++;
if (*p) /* numbers remain in line */
continue;
break; /* otherwise get next line */
}
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (i = 0; i < n; i++)
printf ("v[%d]=% g\n", i, v[i]);
return 0;
}
Example Input File
$ cat dat/strtod_vect.txt
1 -2 3.1 0xf 0xcc
Example Use/Output
$ ./bin/strtod_vect dat/strtod_vect.txt
v[0]= 1
v[1]=-2
v[2]= 3.1
v[3]= 15
v[4]= 204
Look things over and let me know if you have further questions. You can check strtod(3) - Linux man page for further details and error checking that can be done.
I have a problem, I need to make a program which will compare two files.
If in first file I have:
Milk
Sugar
Eggs
and in the second file I have
Vanilla
Soda
Sugar
I want to show the the line which appear in both files.
I don't have a lot of experience with c, but I tried something.
But my question is how I will show Sugar as output if they are not on the same line?
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define MAX 100
void equal (char*lineone,char*linetwo){
if(strcmp(lineone,linetwo)==0){
printf("%s",lineone);
}
}
int main(){
FILE *fp1,*fp2;
fp1=fopen("D:/aici/file1.txt","r");
fp2=fopen("D:/aici/file2.txt","r");
char buff[MAX],buff1[MAX];
int i=0;
while((fgets(buff,MAX,fp1)!=NULL)&&(fgets(buff1,MAX,fp2))!=NULL){
//i++;
equal(buff,buff1);
}
}
What you should do (for performence reasons) is to save all the words in to two buffers and then compare them.
But , you can also do it with a little change in your implementation ,
Just need to seperate the loop to one main loop and one inner loop so you will get the effect that for each word in file 1 it will compare all words in file 2, again , very slow method when comparing to just save all the words first and only then compare each other.
void equal (char*lione,char*linetwo){
if(strcmp(lione,linetwo)==0){
printf("%s",lineone);
}
}
int main(){
FILE *fp1,*fp2;
fp1=fopen("D:/aici/file1.txt","r");
fp2=fopen("D:/aici/file2.txt","r");
char buff[MAX],buff1[MAX];
int i=0;
while(fgets(buff,MAX,fp1)!=NULL) {
while(fgets(buff1,MAX,fp2))!=NULL){
//i++;
equal(buff,buff1);
}
rewind(fp2);
}
}
Continuing from the comment, whether you continue using fgets (recommended), or you recognize that you can also use fscanf and not worry about removing the '\n' from each word, you need to validate each step of your program. While fscanf may appear easier at first, you may want to brush up on man fscanf and determine how you will control the '\n' that will be left, unread, in each of your file streams.
The following is a short example, continuing with fgets, showing how you can test for, and remove, each of the trailing '\n' read and included in your buff by fgets. (as well as reasonable validations for each step). (note: I'm presuming that since your input is a single word, a 256-char buffer is sufficient -- given the longest word in the unabridged dictionary is 28 characters, but you can also validate whether fgets has made a complete read of each line, or if additional characters remain unread)
The following code expects the filenames for each of the files to be given as the first two arguments to the program.
#include <stdio.h>
#include <string.h>
#define MAXC 256
int main (int argc, char **argv) {
if (argc < 3) { /* validate 2 arguments given */
fprintf (stderr, "error: insufficient input.\n"
"usage: %s file1 file2\n", argv[0]);
return 1;
}
char buf1[MAXC] = "", /* declare buf1 */
buf2[MAXC] = ""; /* declare buf2 */
FILE *f1 = fopen (argv[1], "r"), /* open file 1 */
*f2 = fopen (argv[2], "r"); /* open file 2 */
if (!f1) { /* validate file 1 open for reading */
fprintf (stderr, "file open failed '%s'\n", argv[1]);
return 1;
}
if (!f2) { /* validate file 2 open for reading */
fprintf (stderr, "file open failed '%s'\n", argv[2]);
return 1;
}
while (fgets (buf1, MAXC, f1)) { /* read each word in file 1 */
size_t len1 = strlen (buf1); /* get length */
if (len1 && buf1[len1 - 1] == '\n')
buf1[--len1] = 0; /* overwrite '\n' with nul-byte */
while (fgets (buf2, MAXC, f2)) { /* read each in file 2 */
size_t len2 = strlen (buf2);
if (len2 && buf2[len2 - 1] == '\n')
buf2[--len2] = 0; /* overwrite '\n' with nul-byte */
if (len1 != len2) /* if lengths differ, not equal */
continue; /* get next word from file 2 */
if (strcmp (buf1, buf2) == 0) /* compare strings */
printf ("%s\n", buf1); /* print if equal */
}
rewind (f2); /* rewind f2, clear EOF */
}
fclose (f1); /* close f1 */
fclose (f2); /* close f2 */
return 0;
}
(note: the length check if (len1 != len2) is just an efficiency check that prevents calling strcmp unless the words are equal in length. A simple comparison on the lengths (which you already have) is much less expensive than a full function call to strcmp every time. (note, this is a really small savings, that you can remove if you like))
Input Files (intentionally no POSIX-eol)
The datafiles were intentionally created without POSIX end-of-lines to demonstrate it makes no difference to the outcome if you properly handle the newline removal.
$ cat dat/f1cmp.txt
Milk
Sugar
Eggs
$ cat dat/f2cmp.txt
Vanilla
Soda
Sugar
Example Use/Output
$ ./bin/fgets_cmp_words dat/f1cmp.txt dat/f2cmp.txt
Sugar
Look things over and concentrate on the validations. Let me know if you have any further questions.
Showing Where Words Differ
To show where the words differ, you only need to modify the inner loop. You can do a simple comparison by looping over the characters in buf1 and buf2 and stopping when the first difference is located. You can continue for the two cases above (1) where the lengths differ; and (2) where the return of strcmp != 0, or you can just do a single test following a non-zero return from strcmp.
The modifications to the inner-loop above is shown below. I don't know what output format you are looking for, so I have just output the words that differ and shown the character at which the words begin to differ (zero-based indexing):
while (fgets (buf2, MAXC, f2)) { /* read each in file 2 */
size_t len2 = strlen (buf2);
int i = 0;
if (len2 && buf2[len2 - 1] == '\n')
buf2[--len2] = 0; /* overwrite '\n' with nul-byte */
if (len1 != len2) { /* if lengths differ, not equal */
/* locate & output difference */
for (i = 0; buf1[i] == buf2[i]; i++) {}
printf ("%s & %s differ at char %d (%c != %c)\n",
buf1, buf2, i, buf1[i], buf2[i]);
continue; /* get next word from file 2 */
}
if (strcmp (buf1, buf2) == 0) /* compare strings */
printf ("%s\n", buf1); /* print if equal */
else { /* locate & output difference */
for (i = 0; buf1[i] == buf2[i]; i++) {}
printf ("%s & %s differ at char %d (%c != %c)\n",
buf1, buf2, i, buf1[i], buf2[i]);
}
}
Example Use/Output
$ ./bin/fgets_cmp_wrds dat/f1cmp.txt dat/f2cmp.txt
Milk & Vanilla differ at char 0 (M != V)
Milk & Soda differ at char 0 (M != S)
Milk & Sugar differ at char 0 (M != S)
Sugar & Vanilla differ at char 0 (S != V)
Sugar & Soda differ at char 1 (u != o)
Sugar
Eggs & Vanilla differ at char 0 (E != V)
Eggs & Soda differ at char 0 (E != S)
Eggs & Sugar differ at char 0 (E != S)
Look it over and let me know if you have further questions.
how can I read rows of ints from a txt file in C.
input.txt
3
5 2 3
1
2 1 3 4
the first 3 means there are 3 lines in all.
I write a c++ version using cin cout sstream
but I wonder how can I make it in C using fscanf or other c functions.
I need to handle each line of integers separately.
I know I can use getline to read the whole line into a buffer, then parse the string buffer to get the integers.
Can I just use fscanf?
What you ultimately want to do is free yourself from having to worry about the format of your inputfile. You want a routine that is flexible enough to read each row and parse the integers in each row and allocate memory accordingly. That greatly improves the flexibility of your routine and minimizes the amount of recoding required.
As you can tell from the comments there are many, many, many valid ways to approach this problem. The following is a quick hack at reading all integers in a file into an array, printing the array, and then cleaning up and freeing the memory allocated during the program. (note: the checks for reallocating are shown in comments, but omitted for brevity).
Note too that the storage for the array is allocated with calloc which allocates and sets the memory to 0. This frees you from the requirement of keeping a persistent row and column count. You can simply iterate over values in the array and stop when you encounter an uninitialized value. Take a look over the code and let me know if you have any questions:
#include <stdio.h>
#include <stdlib.h>
#define MROWS 100
#define MCOLS 20
int main (int argc, char **argv) {
if (argc < 2) {
fprintf (stderr, "error: insufficient input. usage: %s filename\n", argv[0]);
return 1;
}
FILE *fp = fopen (argv[1], "r");
if (!fp) {
fprintf (stderr, "error: file open failed for '%s'.\n", argv[1]);
return 1;
}
char *line = NULL; /* NULL forces getline to allocate */
size_t n = 0; /* max chars to read (0 - no limit) */
ssize_t nchr = 0; /* number of chars actually read */
int **array = NULL; /* array of ptrs to array of int */
size_t ridx = 0; /* row index value */
size_t cidx = 0; /* col index value */
char *endptr = NULL; /* endptr to use with strtol */
/* allocate MROWS (100) pointers to array of int */
if (!(array = calloc (MROWS, sizeof *array))) {
fprintf (stderr, "error: array allocation failed\n");
return 1;
}
/* read each line in file */
while ((nchr = getline (&line, &n, fp)) != -1)
{
/* strip newline or carriage return (not req'd) */
while (line[nchr-1] == '\r' || line[nchr-1] == '\n')
line[--nchr] = 0;
if (!nchr) /* if line is blank, skip */
continue;
/* allocate MCOLS (20) ints for array[ridx] */
if (!(array[ridx] = calloc (MCOLS, sizeof **array))) {
fprintf (stderr, "error: array[%zd] allocation failed\n", ridx);
return 1;
}
cidx = 0; /* reset cidx */
char *p = line; /* assign pointer to line */
/* parse each int in line into array */
while ((array[ridx][cidx] = (int)strtol (p, &endptr, 10)) && p != endptr)
{
/* checks for underflow/overflow omitted */
p = endptr; /* increment p */
cidx++; /* increment cidx */
/* test cidx = MCOLS & realloc here */
}
ridx++; /* increment ridx */
/* test for ridx = MROWS & realloc here */
}
/* free memory and close input file */
if (line) free (line);
if (fp) fclose (fp);
printf ("\nArray:\n\n number of rows with data: %zd\n\n", ridx);
/* reset ridx, output array values */
ridx = 0;
while (array[ridx])
{
cidx = 0;
while (array[ridx][cidx])
{
printf (" array[%zd][%zd] = %d\n", ridx, cidx, array[ridx][cidx]);
cidx++;
}
ridx++;
printf ("\n");
}
/* free allocated memory */
ridx = 0;
while (array[ridx])
{
free (array[ridx]);
ridx++;
}
if (array) free (array);
return 0;
}
input file
$ cat dat/intfile.txt
3
5 2 3
1
2 1 3 4
program output
$ ./bin/readintfile dat/intfile.txt
Array:
number of rows with data: 4
array[0][0] = 3
array[1][0] = 5
array[1][1] = 2
array[1][2] = 3
array[2][0] = 1
array[3][0] = 2
array[3][1] = 1
array[3][2] = 3
array[3][3] = 4
In C (not C++) you should combine fgets with sscanf function.
EDIT:
But as an answer for the question "Can I just use fscanf?"
try this example (where usage of fgetc allows using fscanf instead of fgets+sscanf):
int lnNum = 0;
int lnCnt = 0; // line counter
int ch; // single character
// read number of lines
fscanf(f, "%d", &lnNum);
if(lnNum < 1)
{
return 1; // wrong line number
}
// reading numbers line by line
do{
res = fscanf(f, "%d", &num);
// analyse res and process num
// ....
// check the next character
ch = fgetc(f);
if(ch == '\n')
{
lnCnt++; // one more line is finished
}
} while (lnNum > lnCnt && !feof(f) );
NOTE: This code will work when your file has only numbers separated by single '\n' or spaces, for case of letters or combinations as number \n (space before newline) it becomes unstable