sscanf() double & string - c

I am fairly new to the world of programming so please forgive me if this is a common mistake.
I'm trying to scan 3 double values and 3 strings out of one input string but it doesnt continue after the second value.
double total_weight_kg(char *s, int Length) {
double weights[3];
char units[3];
int test = sscanf(s, "%lf, %s, %lf, %s, %lf, %s",
&weights[0], &units[0],
&weights[1], &units[1],
&weights[2], &units[2]);
printf("%i\n", test);
printf("%s\n", &units[0]);
int main(void) {
total_weight_kg("5, g, 1, t, 175, kg", 3);
return 0;
The first print prints out 2 and the second the g.
Furthermore I'd like to compare units[i] in a loop but can't seem to get that working either.
for (int i = 0; i < Length; i++) {
w = weights[i];
if (strcmp(units[i], "kg") == 0) {
weight += w;
}
}
I hope you can help me find a solution for this problem,
edit: Everyting is working as intended now. Thank you very much for your help. ( 19[^,] was one major problem )

There are some problems in your code:
To scan the strings into units, you must define it as a 2D array of char:
char units[3][20];
You should modify the scanf format to stop the word parsing on , and spaces, as suggested by user3386109.
Also modify the printf to pass the array instead of its address.
Here is the modified code:
double total_weight_kg(char *s, int Length) {
double weights[3];
char units[3][20];
int test = sscanf(s, "%lf, %19[^, \n], %lf, %19[^, \n], %lf, %19[^, \n]",
&weights[0], units[0],
&weights[1], units[1],
&weights[2], units[2]);
printf("%i\n", test);
printf("%s\n", units[0]);
...
}
int main(void) {
total_weight_kg("5, g, 1, t, 175, kg", 3);
return 0;
}

Related

How NOT to read float type in scanf when reading type int

I need to write two integers (and nothing else) to variables. It does the validation makes sure that none of args is a string and that they are not empty and excepts division by zero, or when i put float as a first arg but when i put float as a second argument it does not makes an exception. How can i solve it using only stdio.h?
#include <stdio.h>
void sum(int a, int b);
void dif(int a, int b);
void prod(int a, int b);
void qut(int a, int b);
int main() {
int x, z;
int digits = scanf("%d %d", &x, &z);
if (digits != 2) {
printf("n/a\n");
return 2;
}
else {
sum(x, z);
dif(x, z);
prod(x, z);
qut(x, z);
}
return 0;
}
void sum(int a, int b) {
printf("%d ", a + b);
}
void dif(int a, int b) {
printf("%d ", a - b);
}
void prod(int a, int b) {
printf("%d ", a * b);
}
void qut(int a, int b) {
if (a == 0 || b == 0) {
printf("n/a\n");
}
else {
printf("%d\n", a / b);
}
}
Sorry, i understand that the code is quiet simple and my question is quiet dumb :)
Thx!
As mentioned in the comments, scanf is the WRONG TOOL for this job. scanf is notoriously bad at error handling.
Theoretically it's possible — barely possible — to solve this problem using scanf. By the same token, it's possible to drive a screw into a piece of wood using a hammer. But it's a terrible idea. A woodshop teacher who taught his students to drive screws using a hammer would be fired for incompetence. But for some reason we tolerate this kind of incompetence in teachers of beginning programming.
Normally I don't do homework problems here; normally that's a bad idea, too; normally it makes much more sense to have you, the student, do the work and acquire the learning. In the case of boneheaded assignments like this one, though, I have no qualms about giving you a fully-worked-out solution, so you can get your incompetent instructor off your back and go on to learn something more useful. Here is the basic idea:
Read a line of text (a full line), using fgets.
Parse that line using sscanf, ensuring that it contains a number and a number, and nothing else.
Specifically, we'll use %d to read the first integer, and %d to read the second integer, and then we'll use a third %c to pick up whatever character comes next. If that character is anything other than the \n that marks the end of the line, it indicates that the user has typed something wrong, like a string, or the . that's part of a floating-point number.
This is basically the same as user3121023's solution.
int main()
{
char line[100];
int x, z;
char dummy;
if(fgets(line, sizeof(line), stdin) == NULL) return 1;
int digits = sscanf(line, "%d%d%c", &x, &z, &dummy);
if(digits < 2 || digits > 2 && dummy != '\n') {
printf("n/a\n");
return 2;
}
...
See also What can I use for input conversion instead of scanf?
Footnote: The code here has one unfortunate little glitch: If the user types a space after the second number, but before the newline, the code will reject it with n/a. There are ways to fix that, but in my opinion, for this exercise, they're just not worth it; they fall under the "law of diminishing returns". If your users complain, just act like incorrigible software vendors everywhere: remind them that they were supposed to type two numbers and nothing else, and the space they typed after the second number is "something else", so it's THEIR FAULT, and not your bug. :-)
After scanning for the integers, use a loop to scan for one whitespace character. Break out of the loop on a newline.
For any other character, the scan will return 0.
#include <stdio.h>
void sum(int a, int b);
void dif(int a, int b);
void prod(int a, int b);
void qut(int a, int b);
int main() {
char ws[2] = ""; // whitespace
int scanned = 0;
int x, z;
int digits = scanf("%d %d", &x, &z);
if (digits != 2) {
printf("n/a\n");
return 2;
}
while ( ( scanned = scanf( "%1[ \t\n]", ws))) { // scan for 1 whitespace
if ( scanned == EOF) {
fprintf ( stderr, "EOF\n");
return 1;
}
if ( ws[0] == '\n') {
break;
}
}
if ( scanned != 1 || ws[0] != '\n') {
printf("n/a\n");
return 3;
}
else {
sum(x, z);
dif(x, z);
prod(x, z);
qut(x, z);
}
return 0;
}
void sum(int a, int b) {
printf("%d ", a + b);
}
void dif(int a, int b) {
printf("%d ", a - b);
}
void prod(int a, int b) {
printf("%d ", a * b);
}
void qut(int a, int b) {
if (a == 0 || b == 0) {
printf("n/a\n");
}
else {
printf("%d\n", a / b);
}
}

how to: convert the value of a string of char as a double back without atof

I got stucked with the function double ascii_to_float. My function should receives a string of char and give it the value as a double back. I´m not allowed to use atof().
I want to search for a the point in the string, to proof it if its a double. if not it should return -1.
double ascii_to_float(char *textzahl)
{
int x;
double ausgabe;
sprintf(ausgabe,"%s",textzahl);
/* here with -=48, i´m not sure how to code
it right, i just now that i have to decrease with 48.*/
for(x=0; x< strlen(textzahl); x++)
{
if(textzahl[x]=='.')
{
textzahl[x]-=48;
}
else
{
textzahl[x]=-1;
}
}
return ausgabe;
}
The main function is given, so I have to just Write the code of above function.
#include <stdio.h>
#include <string.h>
int main()
{
char text[80];
double zahl2;
printf("\n bitte eine Zahl eingeben:"),
fgets(text, sizeof(text), stdin);
zahl2= ascii_to_float ( text);
if (zahl2==-1.0)
{
printf("\nfehlerhafte Eingabe oder Wert -1");
}
else
{
printf("\ndie Zahl2 lautet: %lf\n",zahl2);
}
}
I didn't follow your terminologies means name of variables, functions... as it is time consuming for me.
Code
#include<stdio.h>
#include<string.h>
double fun(char*);
int main()
{
char str1[]="2356.23", str2[]="234", str3[]="bonap.art" ,str4[]="33.42.2";
printf("%lf, %lf, %lf, %lf", fun(str1),fun(str2),fun(str3),fun(str4));
}
double fun(char *s)
{
int count=0;
int i;
for(i=0; i<=strlen(s)-1; i++)
{
if(s[i]=='.')
{
count++;
}
if(count==2)
{
return -1;
}
if( !((s[i]>=48 && s[i]<=57)|| (s[i]=='.')) )
{
return -1;
}
}
if(count==0)
{
return -1;
}
double d;
sscanf(s,"%lf",&d);
return d;
}
Output
2356.230000, -1.000000, -1.000000, -1.000000
If you see code carefully you understand all. Still I explain some things.
you mentioned that to check given string is double or not you are checking . it contains point or not but that's not enough.
what if string contain 2 . (points) or characters like a, b, *,... So To take care of these two problems I added count, !((s[i]>=48 && s[i]<=57)|| (s[i]=='.')) these conditions respectively. I will not elaborate if you not understand still, you can comment.
I don't understand why you choose sprintf(ausgabe,"%s",textzahl); rather than sscanf(s,"%lf",&d);
Also you can consider strtod float strtod (const char* str, char** endptr); for your question. you can check out here and here

Got some segmentation error when use struct pointer in for loop in C

Here is some simple code that prints struct values
in_hotel_info function is used to get struct inputs.(And yes, I use 'gets' because my professor forced me to use it sadly). And also When I put "0" as an input, it ends and returns its input numbers.
And I used sscanf to scan strings and numbers.
#include <stdio.h>
typedef struct hotel_info hotel;
struct hotel_info
{
char name[30];
int rank;
double popular;
double far;
char breakfast;
};
int in_hotel_info(struct hotel_info *p);
void out_hotel_info(struct hotel_info *p, int N, int G, double D);
int main(void)
{
hotel hotels[100];
hotel *p;
int number = 0, ranks, fars, i;
number = in_hotel_info(hotels);
p = hotels;
printf("%d\n", number);
getchar();
for (; p < p+number; p++)
{
printf("%s %d %lf %lf %c\n", p->name, p->rank, p->popular, p->far, p->breakfast);
}
}
int in_hotel_info(struct hotel_info infos[])
{
char inputs[100];
hotel* p;
p = infos;
int cnt = 0;
while (1)
{
gets(inputs);
if (strcmp(inputs, "0") == 0)
{
break;
}
else
{
sscanf(inputs, "%s %d %lf %lf %c", p->name, &p->rank, &p->popular, &p->far, &p->breakfast);
}
p++;
cnt++;
}
return cnt;
}
The problem is, when I tried to print
for (; p < p+number; p++)
{
printf("%s %d %lf %lf %c\n", p->name, p->rank, p->popular, p->far, p->breakfast);
}
what I expected is
mike 2 3.5 4.24 Y
but I constantly got a segmentation error.
The problem is, when I tried to print
for (; p < p+number; p++)
{
printf("%s %d %lf %lf %c\n", p->name, p->rank, p->popular, p->far, p->breakfast);
}
the problem is p < p+number is always true when number is strictly positive, so the for never ends and you access out of the array with an undefined behavior (your segmentation fault).
you have additional problems
gets is very dangerous to use because it can write out of the array, use fgets or scanf (secifying max length to read), in the considered case you can read a number then check if it is 0 or not
in in_hotel_info in case the user enter more than than entrie you write out of the array, you need to get the max number of element to read in argument
when you read p->name in case the enter name longer than 29 you write out of the array, limit the size using %29s rather than %s. ALso to bypass spaces at the beginning of the name use %29s (with a space before)
you do not check scanf returns 5, so you do not detect invalid inputs
The getchar(); in main is strange

Indexing an array in C returns a Segmentation Fault

I am working on a project that requires me to read user inputs as pairs of integers and then store them in an array. So, I have created a function that does this. However, I for some reason get a segmentation fault everytime the last input is entered. Here is my code:
int userInput(int *arrayPtr){
int numberPairs, i, numberElements;
printf("%d", sizeof(int));
printf("How many pairs of integers? ");
scanf("%d", &numberPairs);
numberElements = numberPairs*2;
arrayPtr = malloc((numberElements*sizeof(int)) + 64);
for(i = 0; i < numberElements; i+=2){
int first,second;
printf("\nEnter pair: ");
printf("Before scanf");
scanf("%d %d", &first, &second);
printf("%d", first);
arrayPtr[i] = first;
arrayPtr[i+1] = second;
}
printf("%d", numberPairs);
return numberPairs;
}
Here is how I call the function:
int main(){
int *arrayPtr, numberPairs;
numberPairs = userInput(arrayPtr);
multiplyPairs(arrayPtr, numberPairs);
free(arrayPtr);
}
At the moment, I am mainly trying to make the for loop execute in its entirety, but for some reason it always seg faults on the last iteration. For example, if my input for the pairs was 1 2, 3 4, 5 6, my ouput would be 1 3 and then a seg fault (this output is referring to the print statement in the for loop). I have spent a few hours trying to debug this code as well as having other students look at it, and I can not figure out what is wrong. If you could point me in the right direction I would greatly appreciate it. Thanks.
UPDATE: I copied and pasted the code into a new file and it works as intended. Thank you to everyone who told me about other elements of my code that were wrong.
You need this:
int userInput(int **arrayPtr){
int numberPairs, i, numberElements;
printf("%d", sizeof(int));
printf("How many pairs of integers? ");
scanf("%d", &numberPairs);
numberElements = numberPairs*2;
*arrayPtr = malloc((numberElements*sizeof(int)) + 64);
for(i = 0; i < numberElements; i+=2){
int first,second;
printf("\nEnter pair: ");
printf("Before scanf");
scanf("%d %d", &first, &second);
printf("%d", first);
(*arrayPtr)[i] = first;
(*arrayPtr)[i+1] = second;
}
printf("%d", numberPairs);
return numberPairs;
}
int main(){
int *arrayPtr, numberPairs;
numberPairs = userInput(&arrayPtr);
multiplyPairs(arrayPtr, numberPairs);
free(arrayPtr);
}
Explanation using a very simple example
You want to write a function that mutiplies the first with it's second argument and stores the value in the third agrument.
So you try this:
void Multiply(int a, int b, int r)
{
r = a * b;
}
int main(){
int result = 0;
Multiply(3, 4, result);
printf ("result = %d\n", result);
return 0;
}
And you expect the output is result = 12. But you get result = 0. The reason is that when a function parameter is modified, the function argument of the caller won't be modified because the parameters are passed by value (it's like that in C and in most other programming languages). BTW what should happen if you dont pass a variable as 3rd argument but a constant: for example Multiply(3, 4, 5); ?
If you want your function to modify an argument, you have to pass a pointer to the argument to the fonction and modify the pointed value in the function:
Following example shows what to do:
void Multiply(int a, int b, int *r)
{
// r points to the variable passed as third argument
*r = a * b;
}
int main(){
int result = 0;
// here we pass the pointer to result
Multiply(3, 4, &result);
printf ("result = %d\n", result);
return 0;
}

C scanf in loop continues automaticly without input

I'm trying to get input in an array, I expect input like the following.
5 (Number of the second dimensions in the array)
2 (Number of the first dimensions in the array)
So we get an array deeln[2][5] in this example. I try to get it with the following code:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool isinarray(int val, int *arr, int size){
int countimp;
for (countimp=0; countimp < size; countimp++) {
if (arr[countimp] == val)
return true;
}
return false;
}
int main(void){
int k, d, ci, cj, ck, ta;
//get input
scanf("%i", &k);
scanf("%i", &d);
int deeln[d][k], temp[k];
for(ci = 0; ci < d; ci++){
printf("d= %i, ci= %i \n", d, ci);
scanf("%s", temp);
for(cj = 0; cj < k; cj++){
deeln[ci][cj] = temp[cj*2]-'0';
}
}
//loop while.
}
But i've got a problem, whenever i try to input, the program runs automaticly without getting any input when it loops around the third scanf for the 2nd or 3rd time. So then i'm not able to input anything.
What to do? Has it something to do with pointers or am i using scanf wrong?
UPDATE:
If I enter a printf after printf("cj is nu %i \n", cj); then the output also just came after the loop was going its own way. and not before i should give more input, using the third scanf.
The solution of my question was quite easy. I found it after thinking of my input. The problem was that in the input, as described, there were spaces. Somehow scanf can't handle with spaces, unless you use some other syntax. But my solution is to just use fgets instead of scanf where I wanted to get the input. So the new and working code is as follows:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool isinarray(int val, int *arr, int size){
int countimp = 0;
for (countimp=0; countimp < size; countimp++) {
if (arr[countimp] == val)
return true;
}
return false;
}
int main(void){
int t, k = 0, d = 0, ci = 0, cj = 0, ta = 0;
//get input
scanf("%i", &k);
scanf("%i", &d);
char temp[20];
int deeln[d][k];
memset(deeln, 0 , sizeof(deeln));
memset(temp, 0 , sizeof(temp));
for(ci = 0; ci < d; ci++){
fgets(temp, 20, stdin);
for(cj = 0; cj < k; cj++){
ta = cj*2;
deeln[ci][cj] = temp[ta]-'0';
}
}
//loop while.
return 1;
}
Thanks for helping everbody, even though we all didn't came to this. But I hope it will help others!
Two places to look:
1)
cj = 0;//initialize cj before using here
scanf("%i", &temp[cj]);//temp is both an array, and an int. Fix your format specifier,
//and use an index operator - temp[?] (not sure I am using the right index)
2)
deeln[ci][cj] = temp[cj*2]-'0'; //fix your logic here (array index will be exceeded)
An example of working code...
int main(void){
int k, d, ci, cj, ck, ta;
//get input
scanf("%i", &k);
scanf("%i", &d);
int deeln[d][k], temp[k];
for(ci = 0; ci < d; ci++){
printf("d= %i, ci= %i \n", d, ci);
for(cj = 0; cj < k; cj++){
if(scanf("%i", &temp[cj]) != EOF)
{
deeln[ci][cj] = temp[cj]-'0';
}
else deeln[ci][cj] = -1;
}
}
getchar();
//loop while.
}
you can play with the index of temp[cj] to make it what you actually want, but I assume you are intending to read from stdin, then populate deeln[][] with that value, for each scanf.
If you want to parse a string containing spaces and digets, "1 3 8 5 3", you could use strtok()
But your code as it is is not reading a string in, it is reading integers.
This is not perfect, you will have to do some debug, but will illustrate strtok(). You have to enter spaces between each digit after indices are selected: i.e.:
3
3
4 6 8
2 4 7
1 2 8
int main(void){
int k, d, ci, cj, ck, ta;
//get input
scanf("%i", &k);
scanf("%i", &d);
char inStr[d][k*5]; //space for up to k 3 digit numbers with 1 space each
char *buf=0;
int deeln[d][k], temp[k];
for(ci = 0; ci < d; ci++){
printf("d= %i, ci= %i \n", d, ci);
if(scanf("%s ", inStr[ci]) != EOF)
{
buf = strtok(inStr[ci], " ");
cj = 0;
while(buf && (cj < k))
{
deeln[ci][cj] = atoi(buf);
cj++;
}
}
}
//getchar();waits for user input, pauses execution
}

Resources