C using scanf() for | delimited string - c

I want to input a few strings then two integers. Whilst the strings are separated by '|', the integers are kept apart by a '.'.
Looking around online I have seen some sort of syntax which involves [^]. I am using this but it is not working at all. Can someone please point out what I should be doing and why what I am doing is wrong?
sscanf(str, "%s[^|],%s[^|],%s[^|],%i[^|],%i[^.]", …);

The syntax is arcane at best — I'd suggest using a different approach such as strtok(), or parsing with string handling functions strchr() etc.
However the first thing you must realise is that the %[^<delimiter-list>] format specifier (a 'scan set' in the jargon, documented by POSIX scanf()
amongst many other places) only extracts string fields — you have to convert the extracted strings to integer if that is what they represent.
Secondly you still have to include the delimiter as a literal match character outside of the format specifier — you have separated the format specifiers with commas where | are in the input stream.
Consider the following:
#include <stdio.h>
int main()
{
char a[32] ;
char b[32] ;
char c[32] ;
char istr[32] ; // Buffer for string representation of i
int i ;
int j ; // j can be converted directly as it is at the end.
// Example string
char str[] = "fieldA|fieldB|fieldC|15.27" ;
int converted = sscanf( str, "%[^|]|%[^|]|%[^|]|%[^.].%i", a, b, c, istr, &j ) ;
// Check istr[] has a field before converting
if( converted == 5 )
{
sscanf( istr, "%i", &i) ;
printf( "%s, %s %s, %d, %d\n", a, b, c, i, j ) ;
}
else
{
printf( "Fail - %d fields converted\n", converted ) ;
}
return 0 ;
}

You must use either [] or s construct, but not both and your format string must incluse the separators.
So you should write something like :
sscanf(str, "%[^|]|%[^|]|...",...)

This seems to work...
#include <stdio.h>
main()
{
char x[32] = "abc|def|123.456.";
char y[20];
char z[20];
int i =0;
int j =0;
sscanf(x,"%[^|]|%[^|]|%d.%d.",y,z,&i,&j);
fprintf(stdout,"1:%s 2:%s 3:%d 4:%d\n",y,z,i,j);
}

Related

how to read multiple variables separated by commas using only C fscanf()

Say Given a text file that looks like this:
a,b,c
x,y,z
where a is a char *, b contains a float and c contains a double.
For an example, the input file can look like this:
apple,$12.34,test130.8
x,y,z
I want to use fscanf() to read a, b, c and assign each one of them to a corresponding variable.
"apple" will be assigned to A of the same data type; "12.34"(not "$12.34") will be assigned to B with a float data type; so on.
My attempt was as follows:
fp = the file pointer
char A[50];
float B;
double C;
fscanf(fp, "%[^,],%[^,],%[^,]\n", A, B, C);
But I realized that %[^,]can only specify type char *; ergo, I'm not allowed to assign type char * to a float or double variable.
Is there a way to parse %[^,] to make it only specifies type float?
if I only use this:
fscanf(fp, "%s,%f,%lf\n", A, B, C);
It will be thrown off by the "$" in "12.34", and it will give me 0.000000.
Using sscanf() (instead of fscanf()) for ease of testing:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *s = "apple,$12.34,test130.8\npear,$23.45,abc";
for(int offset = 0, n;; offset += n) {
char *symbol;
float price;
char *note;
if(sscanf(s + offset, " %m[^,],$%f,%m[^\n]%n", &symbol, &price, &note, &n) != 3) {
break;
}
printf("symbol: %s, price: %f, note: %s\n", symbol, price, note);
free(note);
free(symbol);
}
}
and the matching output (note how it demonstrate the evils of using floating points for money):
symbol: apple, price: 12.340000, note: test130.8
symbol: pear, price: 23.450001, note: abc
I used %m to have scanf() allocate the strings. If I knew the maximum size of the strings I would reuse a fixed size strings instead of dynamically allocating and freeing those.
When using fscanf() instead of break you could use feof() to see if we are done, or if the input is invalid. If it's invalid you may want to resync to the next \n with fsccnf(..., "%c", ch). For the above s[offset] == '\0' will tell if you are the end but see below.
You may find it's much easier to get a line with fgets(), then use sscanf() similar to above to extract each item. If fails you can report the line and just read the next one. fgets() will return NULL if you have no more data and it leads to cleaner code when you separate I/O and parsing.
There's already an answer from #AllanWind (using dynamic allocation for strings that my old library doesn't do.) Here's an alternative solution (that is much the same.)
First, the input file used for testing:
apple,$12.34,test130.8
banana,$20.67,testing201.45
Then the code using fscanf() with a complicated format string:
int main( void ) {
FILE *fp = fopen( "test.txt", "r" );
if( fp == NULL) {
fprintf( stderr, "fopen() failed\n" );
return -1;
}
char txt[50], word[12];
double dval1, dval2;
while( fscanf( fp, " %49[^,],%*c%lf,%11[^0123456789]%lf", txt, &dval1, word, &dval2 ) == 4 )
printf( "'%s' / %.2lf / '%s' / %.2lf\n", txt, dval1, word, dval2 );
fclose( fp );
return 0;
}
Finally, the output
'apple' / 12.34 / 'test' / 130.80
'banana' / 20.67 / 'testing' / 201.45

Reading separated data from file to different data types in C language

I have trouble when I read these data into (int string float) in C language,
the compiler read the data after the first comma until the end of the line into string (char[])
and do not store any data in a float variable. Hope it understood.
thanks
Blockquote
00979,Jack,133.2
11411,Tony,615.3
24451,Jasmen,655.9
77321,Ahmad,821
09022,Diana,179.3
19091,Tayma,776.6
my code
int flag =1,seat ;
char str[10];
float avg ;
while (flag !=EOF ){
flag=fscanf(in,"%d , %s , %f",&seat,str,&avg);
if(flag==EOF){
break ;
}
printf("%d %s %f\n",seat,str,avg);
}
You should use %[^,] specifier instead of %s specifier to read string until next comma.

Add up digit from char array in c language

I am new to C programming and trying to make a program to add up the digits from the input like this:
input = 12345 <= 5 digit
output = 15 <= add up digit
I try to convert the char index to int but it dosent seems to work! Can anyone help?
Here's my code:
#include <stdio.h>
#include <string.h>
int main(){
char nilai[5];
int j,length,nilai_asli=0,i;
printf("nilai: ");
scanf("%s",&nilai);
length = strlen(nilai);
for(i=0; i<length; i++){
int nilai1 = nilai[i];
printf("%d",nilai1);
}
}
Output:
nilai: 12345
4950515253
You have two problems with the code you show.
First lets talk about the problem you ask about... You display the encoded character value. All characters in C are encoded in one way or another. The most common encoding scheme is called ASCII where the digits are encoded with '0' starting at 48 up to '9' at 57.
Using this knowledge it should be quite easy to figure out a way to convert a digit character to the integer value of the digit: Subtract the character '0'. As in
int nilai1 = nilai[i] - '0'; // "Convert" digit character to its integer value
Now for the second problem: Strings in C are really called null-terminated byte strings. That null-terminated bit is quite important, and all strings functions (like strlen) will look for that to know when the string ends.
When you input five character for the scanf call, the scanf function will write the null-terminator on the sixth position in the five-element array. That is out of bounds and leads to undefined behavior.
You can solve this by either making the array longer, or by telling scanf not to write more characters into the array than it can actually fit:
scanf("%4s", nilai); // Read at most four characters
// which will fit with the terminator in a five-element array
First of all, your buffer isn't big enough. String input is null-terminated, so if you want to read in your output 12345 of 5 numbers, you need a buffer of at least 6 chars:
char nilai[6];
And if your input is bigger than 5 chars, then your buffer has to be bigger, too.
But the problem with adding up the digits is that you're not actually adding up anything. You're just assigning to int nilai1 over and over and discarding the result. Instead, put int nilai1 before the loop and increase it in the loop. Also, to convert from a char to the int it represents, subtract '0'. All in all this part should look like this:
int nilai1 = 0;
for (i = 0; i < length; i++) {
nilai1 += nilai[i] - '0';
}
printf("%d\n", nilai1);
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
This character array
char nilai[5];
can not contain a string with 5 digits. Declare the array with at least one more character to store the terminating zero of a string.
char nilai[6];
In the call of scanf
scanf("%s",&nilai);
remove the operator & before the name nilai. And such a call is unsafe. You could use for example the standard function fgets.
This call
length = strlen(nilai);
is redundant and moreover the variable length should be declared having the type size_t.
This loop
for(i=0; i<length; i++){
int nilai1 = nilai[i];
printf("%d",nilai1);
}
entirely does not make sense.
The program can look the following way
#include <stdio.h>
#include <ctype.h>
int main(void)
{
enum { N = 6 };
char nilai[N];
printf( "nilai: ");
fgets( nilai, sizeof( nilai ), stdin );
int nilai1 = 0;
for ( const char *p = nilai; *p != '\0'; ++p )
{
if ( isdigit( ( unsigned char ) *p ) ) nilai1 += *p - '0';
}
printf( "%d\n", nilai1 );
return 0;
}
Its output might look like
nilai: 12345
15

How to separate character and number from string in c program

For example, I want to separate the string "0013subdivision" into 0013 (as an integer that can do addition, subtraction, etc. not char) and subdivision (as a char itself) in the given string.
This is my code so far:
#include <stdio.h>
#include <stdlib.h>
char location[10]; /* for the input with number and letter */
char x;
int house[10]; /* for the integer that will be separated from the string */
int main()
{
printf("Input: ");
scanf ("%s", &location[x]);
x=0
for (x=0; location[x]!='\0'; x++ );
return 0;
}
Based on my research, the code atoi is used to convert the converted value back to int (if I'm not mistaken) but I don't know when to place the function.
location is char array, if you are reading as string use only %s with string name only, index not required.
scanf ("%s", &location[x]); --> scanf ("%s", location);
After separating only int from char array you need to store one int value into house.
int house[10] --> int house.
Here is the code for extracting only int from string :
char location[10]; /* for the input with number and letter */
int x;
int house = 0 ; /* for the integer that will be separated from the string */
int main()
{
printf("Input: ");
//scanf ("%s", &location[x]);
scanf ("%s", location);
for (x=0; location[x]!='\0'; x++ ) {
if(location[x]>='0' && location[x]<='9') {
house =(house * 10) + (location[x]-48);
}
}
printf("int part = %d \n",house);
return 0;
}
The main problem in the code is
scanf ("%s", &location[x]);
Where you did not impose any limit on the scanning. An input like 0013subdivision will cause out of bound memory access leading to undefined behavior.
Always limit the input size with the length modifier, like, for an array defined as
char location[10]
use the conversion specification like
scanf ("%9s", location); // (i) one element saved for terminating null
// (ii) the array name decays to the pointer to 1st element
//in case of an argument to a function call.
Then, you don't need an integer array to store the extracted integer. A singular variable would suffice.
However, i'd like to suggest a much robust way:
read the user input using fgets()
then, scan the input using sscanf() and appropriate conversion specifier, like %4d%9s or alike.
The most correct way to do this is to use the strto... family of functions from stdlib.h. For example:
printf("%ld\n", strtol(str, NULL, 10));
The atoi family of functions should never be used for any purpose, since they have broken error handling and can be 100% replaced by the strto... functions.
You could use the scanf family of functions but they are needlessly slow and notoriously dangerous, so I don't really see the point of using them here.
If you are interested in implementing the actual copying manually, for learning purposes, it is fairly trivial:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
const char str[] = "0013subdivision";
char number_part [sizeof(str)];
char letter_part [sizeof(str)];
size_t i;
for(i=0; str[i]!='\0' && isdigit(str[i]); i++) // find where the letters start
{}
memcpy(number_part, &str[0], i); // copy digit part
number_part[i] = '\0'; // append null terminator
memcpy(letter_part, &str[i], sizeof(str)-i); // copy letter part + null term
puts(number_part);
puts(letter_part);
printf("%ld\n", strtol(str, NULL, 10));
}
If the string is a run-time variable, you have to use strlen(str)+1 instead of sizeof().
strtol converts string to number and also gives you back the character it stopped on, i.e. first character after number.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char* const input = "0013subdivision";
const char* string;
const long number = strtol(input, &string, 10);
printf("Number: %ld String: '%s'\n", number, string);
// Number: 13 String: 'subdivision'
return 0;
}
https://repl.it/repls/SphericalImpracticalTinamou

Append to C String Based on User Input

I would like to receive an integer x via user input, and return a string with length x in '#'s.
i.e.
x = 4
⇒ "####"
Is a simple solution possible, along the lines of:
printf( "%c * x = %c", hash, x, hash*x);
Currently, my online findings have me creating an iterative program:
#include <stdio.h>
#include <string.h>
//function creates xhash with width '#' characters
void append( char* xhash, char hash, int x )
{
int i = 0;
for ( i = 0; i < x; i++ ) { xhash[i] = hash; }
xhash[x] = '\0';
}
int main ( void )
{
int x = 0;
scanf( "%d", &x );
char xhash[250] = "";
char hash = "#";
append( xhash, hash, x );
printf( "%c", xhash );
return 0;
}
And this gives me a strange design: ▒
I find C strings very confusing, coming from Python where I would use
str.append(i)
or
str = "#" * x
C does not have a full-fledged string data type. "C strings" are just contiguous sequences if char values, terminated by a character with value 0 (which can be spelled '\0').
Very important to your question, though, is that (1) char is an integer data type, (2) different delimiters are used for string literals than for (single-)char literals, and (3) string literals evaluate to pointers to the first character of a C string.
Thus, this ...
char hash = "#";
... attempts to store a pointer in hash, probably resulting in the last byte of the pointer value. Instead, you want this:
char hash = '#';
Moreover, to print a C string via one of the printf()-family functions, you want to use edit descriptor %s:
printf("%s", xhash);
Descriptor %c is for outputting a single character.
A string in C is just an array of bytes followed by a zero byte. That is all that they are.
For a function that creates a string you have two options. You can have the caller pass in a pointer to an array (and the array size, if you're smart) and the function fills it in. The second option is to malloc inside your function and return the pointer to the caller.
Another thing to remember is the standard C library. Your append function is essentially memset followed by setting a zero at the end. You should just call memset instead of doing your own loop.
And I think you are getting weird output because the printf format for a string is %s not %c. The %c format is for a single character.
Finally if you are unfamiliar with C programming you should be compiling will all warnings turned on. The compiler warnings would have told you about the bad printf format string and the invalid char assignment.

Resources