Which format should I use: scanf \string,string,int,int/? - c

I have data in the following format \a,b,c,d/ where a,b are strings of letters and numbers; c, d are integers.
I tried using format \%s,%s,%d,%d/ format to scan it, but that causes a,b,c,d/ to be scanf'ed into the first string instead of only a.
Question:
Is there something I could type in the format in order to achieve desired result?

You can use the following format string to use commas as delimiters :
"\\%[^,],%[^,],%d,%d/"
The idea is to tell scanf to read anything that isn't a comma for each string, then read the delimiting comma and continue.
Here is a (bad and unsafe!) example:
char a[100], b[100];
int c=0, d=0;
scanf("\\%[^','],%[^','],%d,%d/", a, b, &c, &d);
printf("%s, %s, %d, %d\n", a, b, c, d);
In real code, you'll want to write something safer. You can for example use fgets to read a full line of input then reuse the same format string with sscanf to parse it.

Read carefully the documentation of fscanf(3).
You might try something like
char str1[80];
char str2[80];
memset (str1, 0, sizeof(str1));
memset (str2, 0, sizeof(str2));
int n3 = 0, n4 = 0;
int pos = -1;
if (scanf ("\\ %79[A-Za-z0-9], %79[A-Za-z0-9], %d, %d /%n",
str1, str2, &n3, &n4, &pos) >= 4
&& pos > 0) {
// be happy with your input
}
else {
// input failure
}
That won't work if you have a wider notion of letters, like French é or Russian Ы ; both are single letters existing in UTF-8 but represented in several bytes.
I added some spaces (mostly for readability) in the format string (but scanf is often skipping spaces anyway, e.g. for %d). If you don't accept spaces -like an input line such as \AB3T, C54x, 234, 65/ , read each line with getline(3) or fgets(3) and parse it manually (perhaps with the help of sscanf and strtol ...). Notice that %d is skipping spaces! I also am clearing the variables to get more deterministic behavior. Notice that %n gives you the amount of read characters (actually, bytes!) and that scanf returns the number of scanned items.

My straightforward solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a[10010];
gets(a);
int l = strlen(a);
char storded_first[10010], storded_second[10010];
char for_int_c[10010], for_int_d[10010];
int c,d;
char first_symbol, last_symbol;
int i;
int cnt = 0;
int j=0;
for(i=0; i<l; i++)
{
if(a[i]=='\\')
first_symbol = a[i];
else if(a[i]=='/')
last_symbol = a[i];
else if(a[i]==',')
{
cnt++;
j=0;
}
else if(cnt==0)
{
storded_first[j]=a[i];
j++;
}
else if(cnt==1)
{
storded_second[j]=a[i];
j++;
}
else if(cnt==2)
{
for_int_c[j]=a[i];
j++;
}
else if(cnt==3)
{
for_int_d[j]=a[i];
j++;
}
}
c = atoi(for_int_c);
d = atoi(for_int_d);
printf("%c%s, %s, %d, %d%c\n",first_symbol, storded_first, storded_second, c, d, last_symbol);
return 0;
}

Related

How to check if input string is in correct format in C?

A want to check if input string is in right format
"%d/%d"
For example, when the input will be
"3/5"
return 1;
And when the input will be
"3/5f"
return 0;
I have idea to do this using regex, but I had problem to run regex.h on windows.
How to check if input string is in correct format ... ?
A simple test is to append " %n" to a sscanf() format string to store the offset of the scan, if it got that far. Then test the offset to see if it is at the end of the string.
int n = 0;
int a, b;
// v---v----- Tolerate optional white spaces here if desired.
sscanf(s, "%d /%d %n", &a, &b, &n);
if (n > 0 && s[n] == '\0') {
printf("Success %d %d\n", a, b);
} else {
printf("Failure\n");
}
It is not completely clear what you mean by the format "%d/%d".
If you mean that the string should be parsed exactly as if by sscanf(), allowing for 2 decimal numbers separated by a /, each possibly preceded by white space and an optional sign, you can use sscanf() this way:
#include <stdio.h>
int has_valid_format(const char *s) {
int x, y;
char c;
return sscanf(s, "%d/%d%c", &x, &y, &c) == 2;
}
If the format is correct, sscanf() will parse both integers separated by a '/' but not the extra character, thus return 2, the number of successful conversions.
Here is an alternative approach suggested by Jonathan Leffler:
#include <stdio.h>
int has_valid_format(const char *s) {
int x, y, len;
return sscanf(s, "%d/%d%n", &x, &y, &len) == 2 && s[len] == '\0';
}
If you mean to only accept digits, you could use character classes:
#include <stdio.h>
int has_valid_format(const char *s) {
int n = 0;
sscanf(s, "%*[0-9]/%*[0-9]%n", &n);
return n > 0 && !s[n];
}

How to make "overloaded" scanf in C?

Friends how can I make Scanf to take 1 or 2 or 3 numbers depending on input data I give?
sample data 1: "1 2 5"
sample data 2: "1 4"
sample data 3: "4"
if(scanf("%lf",&a)==1 )
{
printf("1 input num\n");
}
else if(scanf(" %lf %lf",&a, &b)==2 )
{
printf("2 input num\n");
}
else if(scanf("%lf %lf %lf",&a, &b, &c)==3 )
{
printf("3 input num\n");
}else
{
printf("Error message.\n");
return 1;
}
You might consider this an answer:
int InputNums=0;
InputNums = scanf("%lf %lf %lf",&a, &b, &c);
if(InputNums!=0)
printf("%d input num\n");
else
printf("Error message.\n");
It works by NOT eating one number and then trying whether instead more numbers could have been read, like your shown code does.
Instead try to read three numbers and then let scanf() tell you how many worked.
But actually I am with the commenters. If you do not have guaranteed syntax in your input (which scanf() is for) then use something else.
This is nicely describing which alternative in which situation AND how to get scanf to work in the same situation:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Scanf already does this for you, and indeed you used the same scanf function with a variable number of arguments. You can look here: How do vararg work in C?
However you don't need to overload scanf, but rather pass to it a string telling what you need to scan. You can do this dynamically by changing the string at runtime.
The code to try is the following:
#include <stdio.h>
int main()
{
char one[] = "%d";
char two[] = "%d%d";
int o1;
int t1,t2;
scanf(one,&o1);
scanf(two,&t1,&t2);
printf("%d %d %d",o1,t1,t2);
return 0;
}
If you must use scanf() ....
"%lf" is a problem as it consumes leading white-space including '\n', so we lost where a line of input might have ended.
Instead first look for leading white-space and see if an '\n' occurs.
#define N 3
double a[N];
count = 0;
while (count < N) {
// Consume leading white-spaces except \n
unsigned char ch = 0;
while (scanf("%c", &ch) == 1 && isspace(ch) && ch != '\n') {
;
}
if (ch == '\n') {
break;
}
// put it back into stdin
ungetc(ch, stdin);
if (scanf("%lf", &a[count]) != 1)) {
break; // EOF or non-numeric text
}
count++;
}
printf("%d values read\n", count);
for (int i=0; i<count; i++) {
printf("%g\n", a[i]);
}
Alterantive to consume various multiple leading whitespaces that only uses scanf() with no ungetc():
// Consume the usual white spaces except \n
scanf("%*[ \t\r\f\v]");
char eol[2];
if (scanf("%1[\n]", eol) == 1) {
break;
}
If the line contains more than N numbers or non-numeric text, some more code needed to report and handle that.
The best solution to problems with scanf and fscanf is usually to use something other than scanf or fscanf. These are remarkably powerful functions, really, but also very difficult to use successfully to handle non-uniform data, including not only variable data but data that may be erronious. They also have numerous quirks and gotchas that, though well documented, regularly trip people up.
Although sscanf() shares many of the characteristics of the other two, it turns out often to be easier to work with in practice. In particular, combining fgets() to read one line at a time with sscanf() to scan the contents of the resulting line is often a convenient workaround for line-based inputs.
For example, if the question is about reading one, two, or three inputs appearing on the same line, then one might approach it this way:
char line[1024]; // 1024 may be overkill, but see below
if (fgets(line, sizeof line, stdin) != NULL) { // else I/O error or end-of-file
double a, b, c;
int n = sscanf(line, "%lf%lf%lf", &a, &b, &c);
if (n < 0) {
puts("Empty or invalid line");
} else {
printf("%d input num\n", n);
}
}
Beware, however, that the above may behave surprisingly if any input line is longer than 1023 characters. It is possible to deal with that, but more complicated code is required.
here is an example of using fgets, strtok and atof to achieve same:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char input[256];
double inputsf[256];
while(1) {
printf(">>> "); fflush(stdout);
char *s = fgets(input, 255, stdin);
if (!s)
break;
int count = 0;
char *t;
while (t = strtok(s, " \n")) {
s = NULL;
inputsf[count++] = atof(t);
}
printf("Found %d inputs\n", count);
for (int i = 0; i < count; i++)
printf(" %lf\n", inputsf[i]);
if (count == 0)
break;
}
return 0;
}
Bases on the #chux-ReinstateMonica comment, here is a piece of code which uses strtod. It skips leading spaces, but has an issue with the tailing spaces at the end of the string. So, some extra checking is needed there, which could be used for error checking as well. The following loop can replace the strtok loop from above.
while(*s) {
char *e;
double val = strtod(s, &e);
if (e == s)
break; // not possible to parse, break the loop
inputsf[count++] = val;
s = e;
}
You can solve your problem using those line of code
#include <stdio.h>
int main(){
int a[100];
int n;
printf("How many data you want to input: ");
scanf("%d", &n);
printf("Sample %d data Input: ", n);
for (int i=0; i <n; i++) {
scanf("%d", &a[i]);
}
printf("Sample data %d: ", n);
for (int i=0; i <n; i++) {
printf("%d ", a[i]);
}
if(n == 1){
printf("\n 1 input num\n");
}else if(n==2){
printf("2 input num\n");
}else if(n==3){
printf("3 input num\n");
}else{
printf("Error");
}
return 0;
}
if you want to take multiple input in single line use this line
int arr[100];
scanf ("%lf %lf %lf", &arr[0], &arr[1], &arr[2]);

scanf is getting skipped, showing segmentation fault [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 2 years ago.
This code says segmentation fault cause the program's scanf isn't working. I used a debugger to find out this. The scanf(num) is skipped. And thus the segmentation fault. Can somebody tell why the scanf is being skipped? I used [^\n] so that scanf can read string with spaces. Help.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
int a, b;
scanf("%d %d", &a, &b);
int sumr, maxr;
int sumc, maxc;
int white[b + 1];
white[0] = -1;
int ele[b][a];
for (int opl = 0; opl < a; opl++)
{
for (int pl = 0; pl < b; pl++)
{
ele[pl][opl] = 0;
}
}
char num[100000];
int c = -1;
c:
c++;
scanf("%[^\n]%*c", num);
int hu = 0;
int len = strlen(num);
white[b] = len;
for (int ji = 0; ji < len; ji++)
{
if (isspace(num[ji]))
{
white[hu] = ji;
hu++;
}
}
for (int ft = 0; ft < b; ft++)
{
int lopl = 1;
for (int koi = white[ft + 1] - 1; koi > white[ft]; koi--)
{
ele[ft][c] += lopl * (num[koi] - '0');
lopl = lopl * 10;
}
}
if (a > c)
goto c;
}
scanf("%[^\n]%*c", num);
As a first step. you should always check the return value of functions that can adveresely affect your program. In other words, something like:
if (scanf("%d %d", &a, &b) != 2) { handleOneProblem(); }
if (scanf("%[^\n]%*c", num) < 1) { handleAnother(); }
If that second one fails, then num will be left containing whatever arbitrary data it contained before the call, and you probably don't want to then use it as if it contains a valid string.
On top of that, you should be aware that some, but not all, scanf format specifiers will gobble up white space before attempting to read the data. For example, %d will first skip over whitespace and then attempt to read an integer. However, format specifiers such as [ and c will not.
And none of them will gobble up whitespace after the field has been read for the format specifier. That means, if you want that done, you need to do it yourself, with a set of functions like:
#include <stdio.h>
int gobbleLineFile(FILE *inFile) {
int ch;
while ((ch = fgetc(inFile)) != '\n' && ch != EOF) {}
return ch;
}
int gobbleLineStdIn(void) { return gobbleLineFile(stdin); }
As an aside, a lot of problems with scanf are caused by mixing those format specifiers that skip white-space, with those that don't. You can code around that as per above suggestion but, if you're expecting the user to give line-based input, it's often better to do everything as line-based, then use sscanf to break apart the lines.
A fairly decent line-based input routine can be found here.
You have to catch the '\n' that was left from the first scanf.
Either change it to: scanf("%d %d\n", &a, &b);
or put a getchar(); right after it.
Because the next reading: scanf("%[^\n]%*c", num); will read until the next '\n', which is the first thing left on the buffer.

Ensuring you're reading a character through scanf

Is there a simple way to make sure you're reading a character through scanf. If it were an integer I'd use a do while loop
do{
printf("enter a number");
fehler = scanf(" %d", &x);
getchar();
} while(fehler!=1);
But I'm not fully sure what to do if the input is meant to be a string. I know the alphabets are stored as ASCII values but the if constraints in the while statement don't seem to be working(unless I'm doing it wrong)
char * temp2;
temp2 = malloc(sizeof(string));
do{
printf("PLease enter a string: ");
scanf(" %s", temp2);
getchar();
} while(temp2 <= 'A' && temp2 <= 'z')
You can't compare a string to a single character. You have to loop through the entire string, checking every character.
#include <ctype.h>
int is_alphabetic(char *str) {
for (int i = 0; str[i]; i++) {
if (!isalpha(str[i])) {
return 0;
}
}
return 1;
}
...
do{
printf("Please enter an alphabetic string: ");
scanf(" %s", temp2);
getchar();
} while(!is_alphabetic(temp2));
You see printf and scanf work independently. Whatever you store be it a character or number is stored in form of a number. Now it depends on the printf function what it demands.
Eg.: If you store 'a' at a location, the number 97 is stored. Now if you print a number it prints 97 and if you demand a character it gives a.
#include <stdio.h>
int main()
{
int i = 97;
printf("%d \n", i);
printf("%c", i);
return 0;
}
See the results. Further char, int , long int are just data types which specify the number of bits that would be resrved for the inputs for the variable.
Execute this program and you'll understand:
#include <stdio.h>
int main()
{
int i;
for (i=97; i <=200 ; i++)
{
printf("%d %c,\t",i,i);
};
return 0;}
This will show you a nmber when printed as a number and then the SAME number read as character.
Note there are no markers in memory to store which type of data it is. It is straightforward stored as number.
scanf is absolutely the wrong tool for this. But if you want to read only alphabetic characters, you can do it easily enough with something like:
char s[32];
if( 1 == scanf(" %31[a-zA-Z]", s) ){ ... }
The %31[a-zA-Z] conversion specifier will match only the literal characters a thru z and A thru Z, and will only consume up to 31 characters of input. You must always use a field width modifier with %s or %[] conversion specifiers to avoid an overflow.

How do I combine two strings and then convert it to an integer in C

I am reading a data file with numbers in it and extracting some of the numbers and converting them into one integer.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE* fp = fopen("data.txt", "r");
int i;
char data[5];
for(i = 0; i < 5; i++)
{
data[i] = fgetc(fp);
}
fclose(fp);
}
I have an array of dates in a char matrix and want to have separate arrays for the date month and year. How do I take any n numbers from the data file and turn them into an n digit integer? I have tried strcat followed by atoi but my lack of understanding of pointers gets in the way and I constantly get error messages?
I/O:
Input data (bank statement):
09,08,2014,"BOOK SHOP",12.34,5.67,
10,08,2014,"CAR MECHANIC",52.44,5.67,
11,08,2014,"CHIP SHOP",67.34,5.67,
The desired output is separate arrays for date, month, year, place of purchase, amount and balance. I have separate arrays for each but the numbers are strings and not integers. How can I convert each column to an integer array?
If you NULL terminate your character array, then it is effectively a string representation of a number as far as C is concerned. You can then just use atoi() directly on it:
int data_int;
char data_str[N+1];
for (i = 0; i < N; i++)
{
data_str[i] = fgetc(fp);
/* to be really sure, you should make sure each character
* you read is a decimal digit from '0' - '9'
*/
}
data_str[N] = '\0';
data_int = atoi(data_str);
I'm assuming you are interested in reading the lines of data like:
09,08,2014,"BOOK SHOP",12.34,5.67,
10,08,2014,"CAR MECHANIC",52.44,5.67,
11,08,2014,"CHIP SHOP",67.34,5.67,
It looks like you can use fscanf(), but you need to be careful:
int day[20];
int month[20];
int year[20];
char name[20][15];
double amount[20];
double balance[20];
for (int i = 0; i < 20; i++)
{
if (fscanf(fp, "%d ,%d ,%d , \" %14[^\"] \" ,%lf ,%lf ,",
&day[i], &month[i], &year[i], name[i],
&amount[i], &balance[i]) != 6)
break;
}
You might not need every one of the spaces, and you'll never know whether the final comma on the line was missing. Note that the code avoids buffer overflows, both by limiting the number of iterations on the loop and by limiting the length of the string field. I chose 15 for the length of the names simply so that it is clear which number is the number of entries and which is the length of each entry.
You might prefer the fgets() and sscanf() approach:
int day[20];
int month[20];
int year[20];
char name[20][15];
double amount[20];
double balance[20];
char buffer[4096];
int i; // Outside loop so it can be accessed after the loop
for (i = 0; i < 20 && fgets(buffer, sizeof(buffer), fp) != 0; i++)
{
if (sscanf(buffer, "%d ,%d ,%d , \" %14[^\"] \" ,%lf ,%lf ,",
&day[i], &month[i], &year[i], name[i],
&amount[i], &balance[i]) != 6)
break;
}
This will reject lines which don't match, whereas the original code using fscanf() directly would work with data like this:
09,08,2014,"BOOK SHOP",12.34,5.67,10,08,2014,"CAR MECHANIC",
52.44,5.67,11,
08,
2014,
"CHIP SHOP",
67.34,
5.67,
The code shown more or less replaces the lines in the question from char data[5]; through the end of the loop. You can add code to print the values read.
for (int j = 0; j < i; j++)
printf("%.4d-%.2d-%.2d %-14s %8.2f %8.2f\n",
year[j], month[j], day[j], name[j], amount[j], balance[j]);

Resources