How can I add together the numbers in a file? - c

I have a large text file. In this file there are some numbers I want to add together.
What I've tried:
int sum = 0, i = 0;
file = fopen(filename, "r");
while ((i = fgetc(file)) != EOF) {
if (isdigit(i)) {
sum++;
}
}
printf("Sum of numbers is: %i", sum);
fclose(file);
But that isdigit(i) is just a counter of how many digits this file contains, not what the sum of the numbers is.
The input is: "This text 15 is very 19 nice."
The result should be: Sum of numbers is: 34

Consider the decimal placement
The missing part in the question's code is accumulating the digits (as opposed to counting the digits with sum++;) AND multiplying by ten the previous accumulated number before adding the next digit.
The answer is in:
number = number * 10 + i - '0';
The - '0' part is converting ASCII digit to a number.
Everything else in the below code is checks to make sure there are no obvious overflows and correctly supporting minus sign also adjacent to the numbers, as well as ignoring digits after the decimal point(s). I'm sure it is not perfect, but the idea here is to provide a working example of how it could be done, rather than a well tested code and using a library call to do it for you.
By popular demand (comments were deleted now) I've added a simple-but-working overflow check:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <error.h>
#include <limits.h>
int main(int argc, char* argv[]) {
int sum = 0, state = 0, i = 0, dir = 1;
unsigned int number = 0, check;
if (argc < 2) {
fprintf(stderr, "Missing filename\n");
return EXIT_FAILURE;
}
char* filename = argv[1];
FILE* file = fopen(filename, "r");
if (!file) {
perror(filename);
return EXIT_FAILURE;
}
while (i != EOF) {
i = fgetc(file);
if (isdigit(i)) {
if (dir) {
state = 1;
check = number;
number = number * 10 + i - '0';
if (check > number || number > INT_MAX) {
fprintf(stderr, "Single number overflow error\n");
fclose(file);
return EXIT_FAILURE;
}
}
} else {
if (state && dir) {
check = number;
if (dir < 0 && sum < 0)
check -= sum;
else if (dir > 0 && sum > 0)
check += sum;
if (check > INT_MAX) {
fprintf(stderr, "Sum overflow error\n");
fclose(file);
return EXIT_FAILURE;
}
sum += number * dir;
number = 0;
}
state = 0;
dir = i == '-' ? -1 : i == '.' ? 0 : 1;
}
}
printf("Sum of numbers is: %i\n", sum);
fclose(file);
return EXIT_SUCCESS;
}
Test run:
$ cat opString.txt
This text 15 is very 19 nice.
$ ./test2 opString.txt
Sum of numbers is: 34
$
And just in case you are on 64bit linux system, and need much higher performance (you mentioned large file) the below code will map the entire file (even file larger than memory, the kernel will handle it nicely) and will not make a library call on every char. In my tests, isdigit() and strtol() slows it down significantly.
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <limits.h>
#include <sys/mman.h>
int addToSum(unsigned int* number, int* sum, int dir, FILE* file) {
unsigned int check;
check = *number;
if (dir < 0 && *sum < 0)
check -= *sum;
else if (dir > 0 && *sum > 0)
check += *sum;
if (check > INT_MAX) {
fprintf(stderr, "Sum overflow error\n");
fclose(file);
exit(EXIT_FAILURE);
}
*sum += *number * dir;
*number = 0;
}
int main(int argc, char* argv[]) {
int sum = 0, state = 0, i = 0, dir = 1;
unsigned int number = 0, check;
if (argc < 2) {
fprintf(stderr, "Missing filename\n");
return EXIT_FAILURE;
}
char* filename = argv[1];
FILE* file = fopen(filename, "r");
if (!file) {
perror(filename);
return EXIT_FAILURE;
}
if (fseek(file, 0L, SEEK_END) < 0) {
perror("fseek failed");
fclose(file);
return EXIT_FAILURE;
}
long fsize = ftell(file);
char* fmap = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fileno(file), 0);
if (fmap == MAP_FAILED) {
perror("map failed");
fclose(file);
return EXIT_FAILURE;
}
long pos = 0;
while (pos < fsize) {
i = fmap[pos++];
if (i >= '0' && i <= '9') {
if (dir) {
state = 1;
check = number;
number = number * 10 + i - '0';
if (check > number || number > INT_MAX) {
fprintf(stderr, "Single number overflow error\n");
fclose(file);
return EXIT_FAILURE;
}
}
} else {
if (state && dir) addToSum(&number, &sum, dir, file);
state = 0;
dir = i == '-' ? -1 : i == '.' ? 0 : 1;
}
}
if (state && dir) addToSum(&number, &sum, dir, file);
printf("Sum of numbers is: %i\n", sum);
fclose(file);
return EXIT_SUCCESS;
}

Input file name: file.txt
This text 15 is very 19 nice.
Output:
Sum of numbers is: 34
Code:
#include <stdio.h>
#include <ctype.h>
int main()
{
int sum = 0, num, i = 0;
int state = 0;
FILE* f;
if ((f = fopen("file.txt", "r")) == NULL)
return -1;
while ((i = fgetc(f)) != EOF) {
switch(state) {
case 0: // processing text
if (isdigit(i)) {
num = i - '0';
state = 1;
}
break;
case 1: // processing number
if (isdigit(i)) {
num *= 10;
num += i - '0';
}
else {
sum += num;
num = 0;
state = 0;
}
break;
}
}
if (state == 1) {
sum += num;
}
printf("Sum of numbers is: %i\n", sum);
fclose(f);
return 0;
}

But that isdigit(i) is just a counter of how many digits this text contents but not whats the sum of the numbers is.
Keep in mind, the function isdigit() reads one character per call. So if it reads the character 9 for example, the value sum should grow by i - '0' (or 57 - 48, or 9). And if there were two characters in sequence, such as 92, reading one character at a time, the value sum would likewise be incremented by 9+2 -> 11, not 92. Given this is what you want, here is how to do it:
The values you have determined are digits are actually ASCII values, so in viewing this table you can see all of the digits will have values from '0' to '9' (or in ASCII, 48 to 57). So in your code you can simply change one line to sum up the value count:
int sum = 0;
file = fopen(filename, "r");
while ((i = fgetc(file)) != EOF) {
if (isdigit(i))
sum += (i - '0');//subtract 48 from every 'i' verified as digit
//Sum will therefore add up values
//between (48-48) to (57-48)
//(or between 0 to 9)
}
printf(f,"Sum of numbers is: %i", sum);
fclose(file);
However, If you want to sum up numeric values represented by a sequence of digits within a buffer, then the code is different. It would require keeping a flag as the buffer content is read.
In pseudo code:
char accumlator[10] = {0}; max possible sequential digits (change as needed)
int found = 0;//flag
int sum = 0;
while ((i = fgetc(file)) != EOF)
{
if (isdigit(i))
{
accumulator[found] = i;
found++;
}
else
{
if(found != 0)
{
sum += atoi(accumulator);
found = 0;
accumulator[0] = 0;
}
}
}
}

The function fgetc only reads a single character that is a potential digit. It does not read a whole number that consist of several digits at once. If you want to read whole numbers, you must change the logic of your program. You can do one of the following:
Use fgetc as you do now and make your program assemble the individual digits into a number, by using the ASCII Code of the digits and converting that to a number using arithmetic. The numerical value of an individual ASCII character digit can be obtained using the expression ascii_code - '0'.
Use fgets instead to read a whole line at once and then use strtol to convert any digits you find into numbers.
Use fscanf() to parse the file and extract the number in one step (not recommended unless you know exactly what you are doing).

Your program only counts the number of digits in the file. Here is a simple solution using getc() to compute the number of all integral numbers in the file without the need for a state machine:
#include <stdio.h>
int count_numbers(const char *filename) {
FILE *fp;
unsigned long long total = 0, current = 0;
int c;
if ((fp = fopen(filename, "r")) == NULL) {
printf("Cannot open input file %s\n", filename);
return -1;
}
while ((c = getc(fp)) != EOF) {
if (c >= '0' && c <= '9') {
current = current * 10 + (c - '0');
} else {
total += current;
current = 0;
}
}
total += current; /* add the last number if at the very end of the file */
printf("Sum of numbers is: %llu\n", total);
fclose(fp);
return 0;
}
Notes:
this program does not handle negative numbers, it ignores negative signs.
it does not handle floating point numbers: processing 1.1 will produce a sum of 2.
very long numbers will produce the result modulo ULLONG_MAX+1 but at least the behavior is defined.

If you want to add all the number strings up in this then you'll have to search for the digits and then convert them from a string to an integer using strtol. Here's how to do that:
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define OVERFLOW_STR "Number cannot be represented in an int!\n"
int main(int argc, char **argv)
{
FILE *file;
char n[12];
char *p = n;
int i = 0, sum = 0, tmp, old_errno;
if(argc != 2)
{
fprintf(stderr, "Usage: %s file\n", argv[0]);
return EXIT_FAILURE;
}
file = fopen(argv[1], "r");
if(!file)
{
perror("Error opening file");
return EXIT_FAILURE;
}
while(i != EOF)
{
while( (i = fgetc(file)) != EOF &&
i != '-' &&
i != '+' &&
!isdigit(i) )
{
/* empty loop */ ;
}
if(i != EOF)
{
do {
if( p == n + sizeof(n) - 1 ||
((*n != '-' || *n != '+') &&
p == n + sizeof(n) - 2) )
{
fprintf(stderr, "Error: " OVERFLOW_STR);
return EXIT_FAILURE;
}
*p++ = i;
} while( (i = fgetc(file)) != EOF && isdigit(i) );
}
else
break;
*p = 0;
old_errno = errno;
errno = 0;
tmp = strtol(n, NULL, 10);
if( tmp == 0 && errno != 0 )
{
perror("Error converting string");
break;
}
errno = old_errno;
sum += tmp;
p = n;
}
printf("Sum of numbers is: %d\n", sum);
fclose(file);
return 0;
}
This is largely error-checked. There may be corner cases that I have left out.
Input (contained in a file whose name is passed as a command-line parameter):
This text 15 is very 19 nice.
Output:
Sum of numbers is: 34

Related

Problem with File I/O in C Programming Language

I am writing a program to create a file of prime numbers.
I am new to C, and thus to its I/O system.
The input is the number before (and including) which all prime numbers are to be written in a prime.csv file. I am trying to make my code efficient by using old primes. But, the subsequent prime of the last prime in the prime.csv file is not being appended. I have been stuck on this problem for a while now. Any help will be appreciated.
primes.c:
#include <stdio.h>
#include <stdlib.h>
int isPrime(FILE *file, unsigned int length, unsigned int number);
void primes(unsigned int number);
int main(int argc, char *argv[])
{
if (argc != 2)
{
perror("Usage: a.exe number");
return 1;
}
unsigned int number = atoi(argv[1]);
primes(number);
return 0;
}
int isPrime(FILE *file, unsigned int length, unsigned int number)
{
fseek(file, 0L, SEEK_SET);
unsigned int factor;
for (int i = 0; i < length; i++)
{
fscanf(file, "%u", &factor);
if (number % factor == 0)
return 0;
}
return 1;
}
void primes(unsigned int number)
{
// Getting Header Info
FILE *file_h = fopen("primes_h.csv", "r");
if (file_h == NULL)
{
perror("Was not able to open the file");
return;
}
unsigned int length;
unsigned int last;
fscanf(file_h, "%u,%u", &length, &last);
fclose(file_h);
// If number already less than or equal to last prime
if (number <= last + 1)
{
puts("Condition already satisfied.");
return;
}
// Adding new primes
FILE *file = fopen("primes.csv", "a+");
if (file == NULL)
{
perror("Was not able to open the file");
return;
}
unsigned int newLast;
unsigned int newLength = length;
for (unsigned int now = last + 2; now <= number; now += 2)
{
if (isPrime(file, newLength, now))
{
fprintf(file, "%u\n", now);
newLast = now;
newLength++;
}
}
fclose(file);
// Editing Header Info
FILE *e_file_h = fopen("primes_h.csv", "w");
if (e_file_h == NULL)
{
perror("Was not able to open the file");
return;
}
fprintf(e_file_h, "%u,%u", newLength, newLast);
fclose(e_file_h);
}
primes.csv:
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
101
103
107
109
and so on...
primes_h.csv:
669,4999
The primes_h.csv contains the header info about the primes.csv in the format: length, last
Reading primes from a file to test a number for primality is very inefficient: you will save a number of divisions, but these savings should be small compared to the overhead of reading from the file system and converting the numbers from text to internal representation. Furthermore, you should stop trying the divisors when they become greater than the square root of the number.
You could instead use an array to store the prime numbers found so far. This array does not need to store more than the prime numbers below the square root of the maximum number.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int primes[46341]; // all primes up to sqrt(INT32_MAX)
int nprimes = 0;
if (argc < 2) {
fprintf(stderr, "primes: missing argument\n");
return 1;
}
int limit = strtol(argv[1], NULL, 0);
FILE *fp = fopen("primes.csv", "w");
if (fp == NULL) {
fprintf(stderr, "primes: cannot open primes.csv\n");
return 1;
}
fprintf(fp, "prime\n");
if (limit >= 2) {
primes[nprimes++] = 2;
fprintf(fp, "2\n");
}
for (int n = 3; n <= limit; n += 2) {
int isprime = 1;
for (int i = 1; i < nprimes; i++) {
int p = primes[i];
if (p * p > n)
break;
if (n % p == 0) {
isprime = 0;
break;
}
}
if (isprime) {
if (nprimes < (int)(sizeof(primes) / sizeof(primes[0])))
primes[nprimes++] = n;
fprintf(fp, "%d\n", n);
}
}
fclose(fp);
return 0;
}
Note however that trial division is not very efficient to enumerate primes numbers up to a limit. A Sieve of Eratosthenes is much faster.

garbage values while dynamic memory allocation

My code for dynamically allocating arrays, even though the Input methods for both arrays pattern and text are same text outputs different values, can anyone solve this issue?
#include<stdio.h>
#include<stdlib.h>
int main() {
int length=5;
int * pattern = malloc(length * sizeof(int));
int * text = malloc(length * sizeof(int));
int pattern_size=0;
int text_size=0;
printf("Enter Pattern:");
char c;
while(c != '$' && scanf("%c",&c) != '\n'){
if(pattern_size >= length)
pattern = realloc(pattern, (length += 10) * sizeof(int));
if(c!=',') pattern[pattern_size] = atoi(&c)+pattern[pattern_size]*10;
else if(c==',') {
pattern_size++;
}
}
printf("\nPlease enter the replacement text:");
// get_array(text,&text_size,length);
char d;
while(d != '$' && scanf("%c",&d) != '\n'){
if(text_size >= length)
text = realloc(text, (length += 10) * sizeof(int));
if(d!=',') text[text_size] = atoi(&d)+text[text_size]*10;
else if(d==',') {
text_size++;
}
}
for(int i=0;i<pattern_size; i++){
printf("%d ",pattern[i]);
}
printf("\n");
for(int i=0;i<text_size; i++){
printf("%d ",text[i]);
}
printf("\n");
return 0;
}
Input
Enter Pattern:1,2,3,4,5,6,7,8,9,0,$
Please enter the replacement text:1,2,3,4,5,6,7,8,9,0,$
OUTPUT
1 2 3 4 5 6 7 8 9 0
1 2 3 4 5 6 10417 8 540155953 540287027
You should ever check the return value of malloc and scanf.
Scanf does not return the element scanned. Please check man 3 scanf
On success, these functions return the number of input items
success‐ fully matched and assigned; this can be fewer than
provided for, or even zero, in the event of an early matching
failure. The value EOF is returned if the end of input is reached
before either the first successful conversion or a matching
failure occurs. EOF is also returned if a read error occurs, in
which case the error indicator for the stream (see ferror(3)) is
set, and errno is set to indicate the error.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int length = 1;
int *pattern = calloc(length, sizeof(int));
if (pattern == NULL) {
fprintf(stderr, "Unable to find free memory\n");
exit(EXIT_FAILURE);
}
int* text = calloc(length, sizeof(int));
if (text == NULL) {
fprintf(stderr, "Unable to find free memory\n");
exit(EXIT_FAILURE);
}
int pattern_size = 0;
int text_size = 0;
printf("Enter Pattern:\n");
char c = ' ';
while (c != '$') {
if (scanf("%c", &c) != 1) {
fprintf(stderr, "Error in scanf\n");
exit(EXIT_FAILURE);
}
if (isdigit(c) != 0) {
pattern[pattern_size] = c - 48;
pattern_size++;
pattern = realloc(pattern, (pattern_size + 1) * sizeof(int));
}
}
printf("\nPlease enter the replacement text:\n");
// get_array(text,&text_size,length);
char d = ' ';
while (d != '$') {
if (scanf("%c", &d) != 1) {
fprintf(stderr, "Error in scanf\n");
exit(EXIT_FAILURE);
}
if (isdigit(d) != 0) {
text[text_size] = d - 48;
text_size++;
text = realloc(text, (text_size + 1) * sizeof(int));
}
}
fprintf(stdout, "\nOUTPUT:\n");
for (int i = 0; i < pattern_size; i++)
printf("%d ", pattern[i]);
printf("\n");
for (int i = 0; i < text_size; i++)
printf("%d ", text[i]);
printf("\n");
return 0;
free(pattern);
free(text);
}
Including ctype.h you canuse the library function int isdigit(char c) that take in input a char and tells you if it is a number between 0 and 9.

C: search for non-number-character in array

I am building a C program which gets a .txt file as an argument. Inside the .txt there are rows of integer numbers, with a space between them, like this:
1 2 3 4
5 6 7 8
...
I am supposed to find out, if a non-integer-character shows up inside the .txt file, like this:
1 2 a 4
...
Since there is no instanceof operator in C, I use an array which contains the numbers from 0-9 and check each character of the .txt-file, if it is either a space or an integer. If it is neither, the program is supposed to exit.
If there are no problems in the file, the program calculates a median and prints the line to stdout.
This is my code:
#include <stdio.h>
#include <ctype.h>
int arrayContains(char value);
int main(int argc, char **argv) {
const int LINESIZE = 255;
if (argc != 2) {
printf("wrong args!");
return -1;
}
char *command1 = argv[1];
FILE *handle = fopen(command1, "r");
if (!handle) {
printf("file not found!");
return -1;
}
int count = 0;
int sum = 0;
int median;
char string[LINESIZE];
while (fgets(string, LINESIZE, handle) != NULL) {
for (int i = 0; i <= sizeof(string) / sizeof(string[0]) - 1; i++) {
printf("%c", string[i]);
if (string[i] == ' ') {
i++;
}
else if (arrayContains(string[i]) == 0) {
count++;
sum += (int)string[i];
}
else {
printf("non-integer-character found!\n");
return -1;
}
}
median = sum / count;
printf("%s\n", string);
printf("%d\n", median);
}
}
int arrayContains(char value) {
const char numbers[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
for (int i = 0; i <= 9; i++) {
if (numbers[i] == value) {
return 0;
}
}
return -1;
}
Now the output of the program is always the first number of the txt-file and immediately after that: "non-integer-character found!".
Which tells me that the comparison between the element of the string from gets() and an element from the constant "numbers" array inside the arrayContains() function, will always result in a return of -1 from the arrayContains() function.
What am I doing wrong?
You should really check out isdigit C function!
#include <ctype.h>
int hasDigit(const char *s)
{
while (*s) {
if (isdigit(*s++) == 0) return 0;
}
return 1;
}
Code above returns 1 on empty string. Watch out! You can use my function instead of your arrayContains. If you want to use your routine, please check out my "version":
int arrayContains(char value) {
return isdigit(value)?0:-1;
}
There are several problems with your code.
This bit matches a space, but will result in you skipping the following character because your loop will also do i++.
if (string[i] == ' ') {
i++;
}
This is not the right way to turn a digit into a number. What you're getting here is the ASCII value of the character rather than the value of the digit. So for example if you have a '1' you're adding 49 to sum rather than 1.
sum += (int)string[i];
As discussed elsewhere, you're better off using isdigit() to identify if you've got a digit character. You can also use isspace() to test to see if you have a space or '\n' character (it covers all whitespace). Which would make your loop statement a lot less complicated as you can process the whole string and easily handle lines that are longer than the size of your buffer.
This code corrects the problems you have
while (fgets(string, LINESIZE, handle) != NULL) {
for (char *pos=string; *pos!='\0'; pos++) {
printf("%c", *pos);
if (isdigit(*pos)) {
count++;
sum += *pos-'0';
} elseif(!isspace(*pos)) {
printf("non-integer-character found!\n");
return -1;
}
}
median = sum / count;
printf("%s\n", string);
printf("%d\n", median);
}
I seem to have solved it:
#include <stdio.h>
#include <ctype.h>
int arrayContains(char value);
int main(int argc, char **argv) {
const int LINESIZE = 255;
if (argc != 2) {
printf("wrong args!");
return -1;
}
char *command1 = argv[1];
FILE *handle = fopen(command1, "r");
if (!handle) {
printf("file not found!");
return -1;
}
int count = 0;
int sum = 0;
int median;
char string[LINESIZE];
while (fgets(string, LINESIZE, handle) != NULL) {
for (int i = 0; i <= sizeof(string) / sizeof(string[0]) - 1; i++) {
printf("%c\n", string[i]);
if (isspace(string[i]) == 0) {
i++;
}
else if (isdigit(string[i]) == 0) {
count++;
sum += (int)string[i];
}
else {
printf("non-integer-character found!\n");
return -1;
}
}
fgets(string, LINESIZE, handle);
}
median = sum / count;
printf("%s\n", string);
printf("%d\n", median);
}
it now kinda does the job as expected.
You use the operator sizeof() which won't return the length of the String but the memory size of the pointer (a size_t so 8 bytes).
I suggest you to use this for your for loop:
for (int i = 0; string[i] != '\0' && string[i] != '\n'; i++) {
...
}
String in C are just a part of memory, it's just like an array and the only way to get the length is to find the end ('\0')
I also suggest you to directly search into the ASCII table. Characters are just number between 0 and 127. Digits are between 48 and 57, a simple condition does the stuff !
if (string[i] <= 48 || string[i] >= 57) {
...
}

C Store number of a text file in an array

Hi i have this text document
Now i want to store only the numbers in an array how can i do it in c language??
www.google.com *** 64
www.victoria.org **** 118
www.example.org *** 120
This should do it:
#include <stdio.h>
// read in up to 10 lines
int LINES[10];
int main(){
int current = 0;
// open file for reading
FILE* file;
file = fopen("file.txt", "r");
// read whole file one char at a time
while (1){
char ch;
if(!fread(&ch, 1, 1, file)){
break;
}
if (ch >= '0' && ch <= '9'){
int val = ch - '0';
LINES[current] *= 10;
LINES[current] += val;
}else if (ch == '\n'){
current += 1;
}
}
// Looping over the results
for (int i = 0; i <= current; i += 1){
printf("Line %d = %d\n", i, LINES[i]);
}
}
There are multiple ways you can do this.
One way is to read the numbers into a temporary char[] array one character at a time with fgetc, then convert it to an int with the use of atoi().
To test if characters are integers, you can use the isdigit function from <ctype.h>, or you can simply test ch >= '0' && ch <= '9', either way works.
Here is some sample code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define NUMLINES 10
#define NUMLEN 5
int main(void) {
FILE *fp;
int LINES[NUMLINES], i, count = 0, ch, blen = 0;
/* static temp buffer, make it bigger if integers will be more than 5 digits */
/* dynamic memory allocation always possible here */
char buffer[NUMLEN+1];
/* opening the file, with error checking */
fp = fopen("urls.txt", "r");
if (!fp) {
fprintf(stderr, "%s\n", "Error reading file");
return 1;
}
/* read each character until EOF */
while ((ch = fgetc(fp)) != EOF) {
/* digit found. add to temp buffer */
if (isdigit(ch)) {
buffer[blen++] = ch;
}
/* stop adding to buffer, now convert and add to array */
if (ch == '\n') {
buffer[blen] = '\0';
LINES[count++] = atoi(buffer);
blen = 0;
}
}
/* print the array */
for (i = 0; i < count; i++) {
printf("LINES[%d] = %d\n", i, LINES[i]);
}
return 0;
}
Which should output:
LINES[0] = 64
LINES[1] = 118
LINES[2] = 120

Convert a set of chars to int from a file

I'm reading:
22:5412:99:00 (...)
From a text file using (ch=fgetc(fp)) != EOF because I don't have only those numbers to read.
Identifying a number is easy with if(ch >= 48 && ch <= 57) but the thing is I want to put those numbers 22, 5412 into an array of integers. However when I read a char it reads part of number since each number is char.
It gets 2 (and not 22 like I want to) and in the next iteration reads the other 2. How can I save each set of numbers into it's own integer?
I hope I was clear enough, thanks!
My idea is to read in each char, and if it is a digit append it to a buffer. Whenever we get a non-digit, we just read the contents of the buffer as a string using sscanf, and clear the buffer for the next value.
#include <stdio.h>
#include <stdlib.h>
int read_buffer(char* buffer, int* sz)
{
int ret;
if (*sz==0) return 0;
buffer[*sz]='\0'; //end the string
sscanf(buffer,"%d", &ret); //read the contents into an int
*sz=0; // clear the buffer
return ret;
}
int main()
{
char buffer[1000];
int sz=0;
char ch;
FILE* input=fopen("input.txt","r");
// "input.txt" contains 22:5412:99:00
while ((ch=fgetc(input))!=EOF)
{
int number;
if (isdigit(ch))
{
buffer[sz++]=ch; // append to buffer
}
else
{
printf("Got %d\n",read_buffer(buffer,&sz)); // read contents of buffer and clear it
}
}
if (sz) // check if EOF occured while we were reading a number
printf("Got %d\n",read_buffer(buffer,&sz));
fclose(input);
return 0;
}
You would need to store the numbers as a string or a char* and use atoi to actually convert it to a number. http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
Assuming your pattern is of the type NN:NNNN:NN:NN, parse on the delimiter, feeding characters into a buffer:
int idx = 0, nIdx = 1;
int firstN, secondN, thirdN, fourthN;
char buf[5];
...
while ((ch=fgetc(fp)) != EOF) {
if (ch != ':') {
buf[idx++] = ch;
}
else {
buf[idx] = '\0';
idx = 0;
switch (nIdx++): {
case 1: firstN = atoi(buf); break;
case 2: secondN = atoi(buf); break;
case 3: thirdN = atoi(buf); break;
}
}
}
buf[idx] = '\0';
fourthN = atoi(buf);
...
I did a full program out of the previous post -- and some testing :-)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
/* fill `array` with at most `siz` values read from the stream `fp` */
/* return the number of elements read */
size_t fillarray(int *array, size_t siz, FILE *fp) {
int ch;
size_t curr = 0;
int advance_index = 0;
while ((ch = fgetc(fp)) != EOF) {
if (isdigit((unsigned char)ch)) {
array[curr] *= 10;
array[curr] += ch - '0';
advance_index = 1;
} else {
if (advance_index) {
advance_index = 0;
curr++;
if (curr == siz) { /* array is full */
break;
}
}
}
}
return curr + advance_index;
}
int main(void) {
int array[1000] = {0};
int n, k;
n = fillarray(array, 1000, stdin);
if (n > 0) {
printf("%d values read:\n", n);
for (k=0; k<n; k++) {
printf(" %d", array[k]);
}
puts("");
} else {
fprintf(stderr, "no data read\n");
}
return 0;
}
And a test run
$ ./a.out
24555:76423 foobar 76235 jgfs(8) jhg x86-64 passw0rd RS232
[CTRL+D]
8 values read:
24555 76423 76235 8 86 64 0 232

Resources