Finding sum of ints in a string - c

I need to output the sum of the numbers that are inside of a sentence.
For example :
input: abc3x casa2 y34zq
output : 3+2+3+4 = 12
I need to read all the sentences include the space to do this, but my loop with getchar doesn't work. Can help me to find the problem?
int main() {
int i = 0;
int somma = 0;
char s[MAX];
printf("inserisci la stringa : ");
scanf("%s",s);
while((s[i] = getchar()) != '\n'){
i++;
if(s[i]>'0' && s[i]<'9'){
somma+= (int)s[i]-(int)'0';
}
}
printf("la somma è = %d", somma);
}
I don’t have to use getchar. I would prefer to use fgets because I know that fgets can read the entire line including the space.

Since you are ok with using fgets() you can read the entire line and then use isdigit() to find the numbers.
FILE *fp;
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
char line[MAX];
if( fgets(line, MAX, fp) == NULL ) { // Read entire line
perror("Error reading file");
return -1;
}
int sum = 0;
int len = strlen(line);
for (int i = 0; i < len; i++) {
if (isdigit( (unsigned char)line[i] )) { // cast handles negative values of line[i]
sum += line[i] - '0'; // Add integer value to sum
}
}
The basic idea is the same, only this loops over a string directly instead of trying to read it with getchar() at each step.

There are two ways to solve your problem.
Get entire string in one go from user
To read entire string, you can use scanf as you are using it. It will store entire string in array (s in your case) and then you can parse this array and peform operations as you are doing. Here limitation would be length of string. You can accept string of the MAX size only as your array is of that much size. If you are okay with this, then your code is correct. All you need to do is remove that getChar() from while.
Read one character at a time.
Alternatively, you can read one character at a time from user and immediately perform operations on that character. In that case, you don't need to declare array. One character variable is sufficient and you can go on accepting data from user. In this case, discard the scanf() and in your while(), accept getChar() output in one character and perform your operation.
P.S. There's one small bug in your while() which will give you incorrect result in few cases.

Related

Program that prints specific characters from a line in a file

This is a programming problem i stumbled upon. It requires some specific stuff to be done and that is the reason that i copy files etc. The problem is that it requires that i print out the last character from onoma, the first character from epithetoand the product of the four digits of afm. The thing is that it must be done by reading the file. My code is the following:
#include <stdio.h>
main()
{
FILE *fp, *fp2;
char ch;
char onoma[12];
char epitheto[25];
char afm[4];
char adt[8];
fp = fopen("C:\\Users\\kostikas\\Desktop\\New folder\\myfile.txt", "w");
printf("Dose onoma: \n");
scanf("%s", &onoma);
printf("Dose epitheto: \n");
scanf("%s", &epitheto);
printf("Dose afm: \n");
scanf("%s", &afm);
printf("Dose adt: \n");
scanf("%s", &adt);
fprintf(fp, "%s \n%s \n%s \n%s \n", onoma, epitheto, afm, adt);
fclose(fp);
fp = fopen("C:\\Users\\kostikas\\Desktop\\New folder\\myfile.txt", "r");
fp2 = fopen("C:\\Users\\kostikas\\Desktop\\New folder\\myfile2.txt", "w");
while((ch = fgetc(fp)) != EOF)
{
fputc(ch, fp2);
}
fclose(fp);
fclose(fp2);
fp2 = fopen("C:\\Users\\kostikas\\Desktop\\New folder\\myfile2.txt", "r");
}
I have absolutely no idea on how to continue from here. I'm utterly baffled. If my post is against community guidelines please let me know and i will delete it. Your help would be greatly appreciated though. Thank you.
This is a bunch of tasks smashed together, any one of which is a challenge to a beginner. Let's break this into parts.
The problem is that it requires that i
print the last character from onoma
print the first character from eponimo
print the product of the four digits of afm.
We'll focus on those one at a time.
The thing is that it must be done by reading the file.
And leave this for later, it just complicates everything. First get the logic working with hard coded values, then worry about where the input comes from.
print the first character from eponimo
Each character can be accessed with eponimo[n] starting at 0. First character is eponimo[0], then eponimo[1], and so on. Printing the first character is just...
char eponimo[] = "Basset hounds got long ears";
printf("%c\n", eponimo[0]);
We use %c, not %s, because it is a single character, not a string which is a pointer to an array of characters.
print the last character from onoma
The last character would be the length of the string, minus 1 because it starts from 0. You get the length of a string with strlen.
char onoma[] = "Oodles of poodles jump der strudel";
size_t onoma_length = strlen(onoma);
printf("%c\n", onoma[onoma_length-1]);
print the product of the four digits of afm.
This is a little trickier. It requires math, loops, and converting characters to integers.
First, check that afm is long enough, again using strlen.
if( strlen(afm) < 4 ) {
fprintf(stderr, "afm must have at least four digits\n");
exit(1);
}
You can also check if the characters are digits with isdigit.
Then we can loop through the first four characters.
char afm[] = "123456";
for( int i = 0; i < 4; i++ ) {
printf("%c\n", afm[i]);
}
Now we need to turn them into integers. Whole strings are done with atoi (ASCII to Integer), but we want single characters. The thing about characters in C is they're just integers and we can do math on them. 0 is 48, 1 is 49, and so on. We take advantage that all the integers are in a sequence.
char afm[] = "123456";
for( int i = 0; i < 4; i++ ) {
// '0' - '0' is 0.
int digit = afm[i] - '0';
printf("%d\n", digit);
}
Note that I've switched to %d for printing an integer (a "digit").
Now we multiply them.
char afm[] = "123456";
int product = 1; // start with 1, not 0, else it will always be 0
for( int i = 0; i < 4; i++ ) {
// '0' - '0' is 0.
int digit = afm[i] - '0';
product *= digit; // same as product = (product * digit)
}
printf("%d\n", product);
Now that you know how to do it with fixed strings, you can substitute what you've read from the file. First, open it for reading and check that it worked. This check will save you a lot of misery.
char filename[] = "C:\\Users\\kostikas\\Desktop\\New folder\\myfile.txt";
fp = fopen(filename, "r"); // open for reading
if( fp == NULL ) {
perror("Could not open input file");
}
Now allocate memory and read lines. scanf reads from "standard input", roughly what you tyope into the program. fscanf reads from a filehandle.
// Allocate space for 10 characters.
// Read only 9 because strings need an extra null character to indicate the end.
char onoma[10];
fscanf(fp, "%9s", onoma);
char eponimo[10];
fscanf(fp, "%9s", eponimo);
char afm[10];
fscanf(fp, "%9s", afm);
// We're done reading, close the file.
fclose(fp);
However, scanf and fscanf have a lot of surprising behaviors. And we need to preallocate our best guess of how much we're going to read and be careful not to read in more than we've allocated.
If at all possible, use getline instead. Most compilers support it. It will allocate memory for you. It doesn't have the caveats of fscanf, but it also doesn't strip the newline off the end like fscanf does.
size_t size = 0;
char *onoma = NULL;
getline(&onoma, &size, fp);
Writing is easier. Open the file for writing, you know how to do that, and use fprintf instead of printf, like fscanf instead of scanf.
fprintf(fp, "%c\n", eponimo[0]);
That should get you going. This exercise is throwing multiple problems at a beginner. Break them up into parts and tackle them one at a time.

Comparing two files char by char - end of file error in C

I have a specific problem. I have to read Strings from two files and compare them char by char, and tell in which row is the difference and for how many chars they differ. I have made pointer and all stuff, but the problem is when it comes to the end of the first file (it needs to read just for the length of the shorter file) I am unable to compare the last String because my for loop goes till the '\n', and in last row there is no \n. But on the other side if I put '\0' in for loop it gives me a wrong result, because it counts '\n' as char as well. How do I handle this problem? Suggestions? I don't want to use strcmp() since I need to count char difference, and there are some other conditions to be fulfilled. Here is my problem:
while(!feof(fPointer)){
zeichnen = 0;
fgets(singleLine, 150, fPointer);
fgets(singleLine2, 150, fPointer2);
length = strlen(singleLine); // save the length of each row, in order to compare them
length2 = strlen(singleLine2);
if(length <= length2){
for(i=0; singleLine[i] != '\n'; i++){
singleLine[i] = tolower(singleLine[i]);
singleLine2[i] = tolower(singleLine2[i]);
if(singleLine[i] != singleLine2[i]){
zeichnen++;
}
}
printf("Zeile: %d \t Zeichnen: %d\n", zeile, zeichnen); // row, char
for(i=0; i < min(length, length2); i++) {
if ( singeLine[i] == '\n' || singleLine2[i] == '\n')
break;
/* Do work */
}
Alternative is to use logical and operator to test two or more conditions in for loop conditional part.
From fgets manual page:
char *fgets(char *s, int size, FILE *stream);
fgets() returns s on success, and NULL on error or when end of file
occurs while no characters have been read.
So you chould have while(true) loop and check both fgets return values for end of input.

While loop through text file stops unexpectedly

I am trying to loop through a text file that contains random content. It's current contents are:
"13 -35 57 - 23723724
12taste-34the+56rain-bow845"
My program should only get the numbers from the file (-35 as a negative number, but not - 23723724 due to the space in between) and no letters or other characters unrelated to the integer.
Currently my code has a while loop that runs through the file and fetches all the decimal values. For some unknown reason however, it stops after 57 (total result is: "13-3557" and then it stops).
I have attempted to iterate over every character seperately but that brought along it's own set of problems and this method at least returns whole numbers.
Here is my code:
int *getIntegers(char *filename, int *pn) {
// Create a dynamic array
int len = 100;
int *numbers = malloc(sizeof(int) * len);
// Source file
FILE *file;
file = fopen(filename, "r");
int i = 0, number = 0;
while(fscanf(file, "%d", &number) > 0) {
numbers[i++] = number;
printf("%d", number);
}
return numbers;
}
EDIT:
I have changed my code and it now retrieves all the numbers, but no spaces.
// Create a dynamic array
int len = 100;
int *numbers = malloc(sizeof(int) * len);
// Source file
FILE *file;
file = fopen(filename, "r");
int i = 0, number = 0;
while(!feof(file)) {
if(fscanf(file, "%d ", &number) > 0) {
numbers[i++] = number;
} else {
clearerr(file);
fgetc(file);
}
}
fclose(file);
return numbers;
When the input stream encounters - and it expects to see an integer, it does not read anything. It stops there.
If you want to continue reading the rest of the numbers, you'll need some code that reads the next characters, discards it, and continues on.
while(!foeof(file) )
{
if ( fscanf(file, "%d", &number) > 0) {
numbers[i++] = number;
printf("%d", number);
else {
clearerr(file); // Clear the error state.
fgetc(file); // Read the next character and discard it.
}
}
Update
To add a space between the numbers in the output, use:
printf("%d ", number);
fscanf doesn't keep looking at its input until it finds something matching its patters. In this case, it encounters the lone -, and unable to parse it into an integer, returns zero. This breaks your loop. You will need to use EOF to break your loop instead.
It's because fscanf sees the lonely '-' and as that's not a valid number it cant parse it and returns 0 which causes your loop to end.
I suggest you use fgets to read the whole line, and then use strtok to separate on space, and strtol to convert the tokenized strings to numbers.

C file handling query

So I have a program that takes user input and compares it to a specific line in a file, however the final line will always be credited as incorrect, so can someone solve this for me?, thanks.
File content (just a list of random words)
Baby
Milk
Car
Face
Library
Disc
Lollipop
Suck
Food
Pig
(libraries are stdio,conio and string)
char text[100], blank[100];
int c = 0, d = 0;
void space(void);
int main()
{
int loop = 0;
char str[512];
char string[512];
int line = 1;
int dis = 1;
int score = 0;
char text[64];
FILE *fd;
fd = fopen("Student Usernames.txt", "r"); // Should be test
if (fd == NULL)
{
printf("Failed to open file\n");
exit(1);
}
do
{
printf("Enter the string: ");
gets(text);
while (text[c] != '\0')
{
if (!(text[c] == ' ' && text[c] == ' '))
{
string[d] = text[c];
d++;
}
c++;
}
string[d] = '\0';
printf("Text after removing blanks\n%s\n", string);
getch();
for(loop = 0;loop<line;++loop)
{
fgets(str, sizeof(str), fd);
}
printf("\nLine %d: %s\n", dis, str);
dis=dis+1;
str[strlen(str)-1] = '\0';
if(strcmp(string,str) == 0 )
{
printf("Match\n");
score=score+2;
}
else
{
printf("Nope\n");
score=score+1;
}
getch();
c=0;
d=0;
}
while(!feof(fd));
printf("Score: %d",score);
getch();
}
For any input on the last line, the output will always be incorrect, I believe this is something to do with the for loop not turning it into the next variable, but seeing as the <= notation makes this program worse, I really just need a simple fix for the program thanks.
Some observations:
You must never use gets (it is not even in the C11 standard anymore). Instead of gets(text) use fgets(text, sizeof(text), stdin) – this way a long input will not overflow the text array.
There will be stuff printed at the end because you don't check the return value of either the gets or the fgets, so when end of file occurs for either the file or for user input the rest of that iteration still runs. fgets returns NULL if it didn't read anything – check for that instead of using feof.
You remove newlines from the file input but not from the user input, so the comparison will always fail when you switch from gets to fgets (which doesn't strip linefeeds). The second (otherwise pointless) comparison of text[c] against ' ' should be against '\n'.
edit: Also, in case the last line of your file does not end in a linefeed, the comparison will fail on the last line because you don't check if the last character is a linefeed before you remove it.
The for (loop = 0; loop < line; ++loop) -loop is pointless because line is always 1, so the body is only executed once.
You have unnecessarily global variables which the program hard to follow. And, for instance, your local text[64] overshadows the global text[100], so if you think you are modifying the global buffer, you are not. If your code is complete, none of the variables should be global.
The function getch() is non-standard. There is no easy direct replacement, so you may just accept that you are not writing portable code, but it's something to be aware of.

rle compression algorithm c

I have to do a rle algorithm in c with the escape character (Q)
example if i have an input like: AAAAAAABBBCCCDDDDDDEFG
the output have to be: QA7BBBCCCQD6FFG
this is the code that i made:
#include <stdio.h>
#include <stdlib.h>
void main()
{
FILE *source = fopen("Test.txt", "r");
FILE *destination = fopen("Dest.txt", "w");
char carCorrente; //in english: currentChar
char carSucc; // in english: nextChar
int count = 1;
while(fread(&carCorrente, sizeof(char),1, source) != 0) {
if (fread(&carCorrente, sizeof(char),1, source) == 0){
if(count<=3){
for(int i=0;i<count;i++){
fprintf(destination,"%c",carCorrente);
}
}
else {
fwrite("Q",sizeof(char),1,destination);
fprintf(destination,"%c",carCorrente);
fprintf(destination,"%d",count);
}
break;
}
else fseek(source,-1*sizeof(char), SEEK_CUR);
while (fread(&carSucc, sizeof(char), 1, source) != 0) {
if (carCorrente == carSucc) {
count++;
}
else {
if(count<=3){
for(int i=0;i<count;i++){
fprintf(destination,"%c",carCorrente);
}
}
else {
fwrite("Q",sizeof(char),1,destination);
fprintf(destination,"%c",carCorrente);
fprintf(destination,"%d",count);
}
count = 1;
goto OUT;
}
}
OUT:fseek(source,-1*sizeof(char), SEEK_CUR); //exit 2° while
}
}
the problem is when i have an input like this: ABBBCCCDDDDDEFGD
in this case the output is: QB4CCCQD5FFDD
and i don't know why :(
There is no need to use Fseek to rewind as u have done , Here is a code that is have written without using it by using simple counter & current sequence character.
C implementation:
#include<stdio.h>
#include<stdlib.h>
void main()
{
FILE *source = fopen("Test.txt", "r");
FILE *destination = fopen("Dest.txt", "w");
char currentChar;
char seqChar;
int count = 0;
while(1) {
int flag = (fread(&currentChar, sizeof(char),1, source) == 0);
if(flag||seqChar!=currentChar) {
if(count>3) {
char ch = 'Q';
int k = count;
char str[100];
int digits = sprintf(str,"%d",count);
fwrite(&ch,sizeof(ch),1,destination);
fwrite(&seqChar,sizeof(ch),1,destination);
fwrite(&str,sizeof(char)*digits,1,destination);
}
else {
for(int i=0;i<count;i++)
fwrite(&seqChar,sizeof(char),1,destination);
}
seqChar = currentChar;
count =1;
}
else count++;
if(flag)
break;
}
fclose(source);
fclose(destination);
}
Your code has various problems. First, I'm not sure whether you should read straight from the file. In your case, it might be better to read the source string to a text buffer first with fgets and then do the encoding. (I think in your assignment, you should only encode letters. If source is a regular text file, it will have at least one newline.)
But let's assume that you need to read straight from the disk: You don't have to go backwards. You already habe two variables for the current and the next char. Read the next char from disk once. Before reading further "next chars", assign the :
int carSucc, carCorr; // should be ints for getc
carSucc = getc(source); // read next character once before loop
while (carSucc != EOF) { // test for end of input stream
int carCorr = next; // this turn's char is last turn's "next"
carSucc = getc(source);
// ... encode ...
}
The going forward and backward makes the loop complicated. Besides, what happens if the second read read zero characters, i.e. has reached the end of the file? Then you backtrace once and go into the second loop. That doesn't look as if it was intended.
Try to go only forward, and use the loop above as base for your encoding.
I think the major problem in your approach is that it's way too complicated with multiple different places where you read input and seek around in the input. RLE can be done in one pass, there should not be a need to seek to the previous characters. One way to solve this is to change the logic into looking at the previous characters and how many times they have been repeated, instead of trying to look ahead at future characters. For instance:
int repeatCount = 0;
int previousChar = EOF;
int currentChar; // type changed to 'int' for fgetc input
while ((currentChar = fgetc(source)) != EOF) {
if (currentChar != previousChar) {
// print out the previous run of repeated characters
outputRLE(previousChar, repeatCount, destination);
// start a new run with the current character
previousChar = currentChar;
repeatCount = 1;
} else {
// same character repeated
++repeatCount;
}
}
// output the final run of characters at end of input
outputRLE(previousChar, repeatCount, destination);
Then you can just implement outputRLE to do the output to print out a run of the character c repeated count times (note that count can be 0); here's the function declaration:
void outputRLE(const int c, const int count, FILE * const destination)
You can do it pretty much the same way as in your current code, although it can be simplified greatly by combining the fwrite and two fprintfs to a single fprintf. Also, you might want to think what happens if the escape character 'Q' appears in the input, or if there is a run of 10 or more repeated characters. Deal with those cases in outputRLE.
An unrelated problem in your code is that the return type of main should be int, not void.
Thank you so much, i fixed my algorithm.
The problem was a variable, in the first if after the while.
Before
if (fread(&carCorrente, sizeof(char),1, source) == 0)
now
if (fread(&carSucc, sizeof(char),1, source) == 0){
for sure all my algorithm is wild. I mean it is too much slow!
i made a test with my version and with the version of Vikram Bhat and i saw how much my algorithm losts time.
For sure with getc() i can save more time.
now i'm thinking about the encoding (decompression) and i can see a little problem.
example:
if i have an input like: QA7QQBQ33TQQ10QQQ
how can i recognize which is the escape character ???
thanks

Resources