What's wrong with this sscanf() format string? - c

I'm trying to parse a simple string: a character from the set "rgbcmyw" followed by a character form the set "slh" then an integer.
risk:9008:~$ cat test-scanf.c
#include <stdio.h>
int main(int argc, char ** argv) {
char c,m;
int s;
printf("Scanned %d elements.\n", sscanf(argv[1], "%[rgbcmyw]%[slh]%d", &c, &m, &s));
printf("Scanned:\n\tc = %c (%d)\n\tm = %c (%d)\n\ts = %d\n",c,c,m,m,s);
return 0;
}
risk:9012:~$ gcc test-scanf.c && ./a.out rs40
Scanned 3 elements.
Scanned:
c = (0)
m = s (115)
s = 40
risk:9013:~$
Why is zero being assigned to 'c'?
EDIT: The solution
One needs space for the character being scanned plus a nul termination:
#include <stdio.h>
int main(int argc, char ** argv) {
char c[2],m[2]; /* Need space for the character *and* the 'nul' termination. */
int s;
printf("Scanned %d elements.\n", sscanf(argv[1], "%[rgbcmyw]%[slh]%d", c, m, &s));
printf("Scanned:\n\tc = %s\n\tm = %s\n\ts = %d\n",c,m,s);
return 0;
}

You are using a string conversion specifier and a char pointer. %[foo] expects a pointer to char (and there must be enough room for all the characters in the string, plus a terminating null byte), not simply a pointer to a char.

Your code is passing the wrong type of parameters to sscanf(). The "%[] specifier expects a char * pointer.

Related

C split string into chunks using sscanf?

I'm trying to write a program to split a string into the first 3 characters, the next 3 characters, and then the last 3 characters for the specific string.
int main(int argc, char *argv[])
{
char str[9] = "AbcDefGhi";
char first[3], second[3], third[3];
int ret;
ret = sscanf(str, "%3s%3s%3s", first, second, third);
printf("# variables: %i\n", ret);
printf("1: %s\n", first);
printf("2: %s\n", second);
printf("3: %s\n", third);
printf("whoops");
return 0;
}
But when I run it, the output is
# variables: 3
1: AbcDefGhi
2: DefGhi
3: Ghi
whoops
And I want
# variables: 3
1: Abc
2: Def
3: Ghi
whoops
Any help is appreciated.
man scanf:
String input conversions store a terminating null byte ('\0') to mark the end of the input; the maximum field width does not include this terminator.
That is, the buffer to store the string needs to be at least one byte larger than the maximum field width to account for the NUL terminator. So increase the size of all your arrays to account for the NUL terminator.
char str[] = "AbcDefGhi";
char first[4], second[4], third[4];
I'm not sure if you need to do it without any functions from libraries, but I have created a code that is doing exactly what you want.
Let us know if it's to complicated for you.
#include <stdio.h>
#include <stdlib.h>
char *split(const char *str, size_t size){
static const char *p=NULL;
char *temp;
int i;
if(str != NULL) p=str;
if(p==NULL || *p=='\0') return NULL;
temp=(char*)malloc((size+1)*sizeof(char));
for(i=0;*p && i<size;++i){
temp[i]=*p++;
}
temp[i]='\0';
return temp;
}
int main(){
char *p = "AbcDefGhi";
char *temp[5];
int i,j;
for(i=0;NULL!=(p=split(p, 3));p=NULL)
temp[i++]=p;
for(j=0;j<i;++j){
printf("%d: %s\n",j, temp[j]);
free(temp[j]);
}
printf("whoops");
return 0;
}

Is there a possible way to use char in strcmp?

I have this program that's supposed to be a 'chat simulator', the only thing it's supposed to do now is replying 'Hello!' when the user types 'Hello'.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
int main()
{
printf("Chat simulator!\n");
do {
char x;
printf("[User1] ");
scanf("%s",&x);
if (strcmp (x,"Hello") == 0)
{
Sleep(1500);
printf("[User2] Hello!\n");
}
else {}
} while(1);
}
I know that strcmp is only for const char *, not a single char, and that's the problem here, but I couldn't find any other solution for this, since I need to use char x in scanf, so it can't be a const char *. Also it may be possible that I'm using strcmp wrong.
Code:Blocks warning:
passing argument 1 of 'strcmp' makes pointer from integer without a cast*
expected 'const char *' but argument is of type 'char'*
Edit:
So I changed the char to char[16] as #robin.koch told me, and it's all working as it should. Thanks!
You cannot compare a string with a char with strcmp, but it is easy to do by hand:
int samechar(const char *str, char c) {
return *str == c && (c == '\0' || str[1] == '\0');
}
The above function however is not what you need for you problem:
You should read a string from the user, not a single char.
scanf() needs a pointer to a char array for the conversion specifier %s.
Furthermore you should specify the maximum number of characters to store into the this array to avoid potential a buffer overflow.
Finally, scanf() will only read a single word. You probably want to read a full line from the user. Use fgets() for this.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(void) {
printf("Chat simulator!\n");
for (;;) {
char buf[100];
printf("[User1] ");
if (!fgets(buf, sizeof buf, stdin))
break;
buf[strcspn(buf, "\n")] = '\0'; /* strip the newline if present */
if (strcmp(buf, "Hello") == 0) {
printf("[User2] Hello!\n");
}
}
return 0;
}
As others have pointed out, you're trying to store a string into a char variable using scanf when chars are only meant to store one character. You should you use a char * or char[] variable to hold your string instead. So change
char x;
printf("[User1] ");
scanf("%s",&x);
//...rest of your code...
to
char * x = malloc(sizeof(char) * 10); //can hold up to ten characters
printf("[User1] ");
scanf("%s",x);
//...rest of your code...
free(x);
Note that if you just want to use a char array instead of a pointer you can replace the first line above with something like char x[10]; and get rid of free(x);

using sscanf() read from command line [duplicate]

I need to get argv[1] and argv[2] to different types. I found that I could only use sscanf() once or the next string in argv cannot be retrieved.
Here's my code.
int main( int argc, char *argv[])
{
char t;
float temp;
sscanf(argv[1], "-%[cf]",&t);
sscanf(argv[2], "%f", &temp);
return 0;
}
Only the first sscanf() can get the formatted value.
How could I also get done with argv[2]?
Attempt to save string data in a char leading to undefined behavior (UB).
"%[]" expects to match a character array.
// char t;
// sscanf(argv[1], "-%[cf]",&t);
char t[100];
if (sscanf(argv[1], "-%99[cf]",t) != 1) Handle_Failure();
Recommend:
Add the width limit, like 99, to limit string input. Set to 1 less than the size of t.
Check the return value of sscanf().

reversing a string in C

#include <stdio.h>
void reverse(int len, char s[], char b[]);
int main() {
char s[5] = "hello";
char b[5];
reverse(5, s, b);
return 0;
}
void reverse(int len, char s[], char b[]) {
int i;
for (i = 0; i < len; i++) {
b[(len - 1) - i] = s[i];
}
printf("%s : %s\n", s, b);
printf("%s", b);
}
Here is my code above in C. When I run it, it switches the string s[] to b[] but b[]also includes s[]. Can someone please thoroughly explain what I'm doing wrong? I really appreciate it.
char s[5] = "hello";
This is wrong, you need one more [6] in order to store the trailing '\0' (same for b)
It's better to omit the array size:
char s[] = "hello";
char b[sizeof(s)];
And you need b[i] = '\0'; after the for loop.
Your string buffers are too small, they must be six characters or more to hold the string "hello". Remember that strings C have a terminating '\0'-character at the end; that won't fit with space for only five characters.
Also, when reversing you never copy the terminating character.
You need b[len - 1] = '\0'; before exiting reverse().
When you pass non-terminated strings to printf()'s "%s" format, you get undefined behavior. Typically it "runs off the end" of the string, printing whatever it happens to find in memory, until it finds a character with the value 0 which causes it to stop.
The %s format specifier expects a string: An array of characters ending in a nul byte. You are not supplying that, so you are getting rubbish results. To hold a string with five characters, you need at least six chars.
every string in c is terminated by \0 which is a null character. so the array size should be enough to hold the string along with null character.
I will suggests to increase the size of array.
important :-
at the last assign b[last_index]='\0';
so that string b can be terminated by \0. otherwise it might give garbage values along with actual data while printing the string b.
In C, you just need to include
#include<string.h>
and use
strrev(a);
where a is the character array or string.
Whereas, your code can be modified too, to be written like this
#include <stdio.h>
void reverse(int len, char s[], char b[]);
int main() {
char s[5] = "hello";
char b[5];
reverse(5, s, b);
return 0;
}
void reverse(int len, char s[], char b[]) {
int i,j;
for (i = 0,j=len-1; i <=j; i++, j--) {
b[j]=a[i];
}
printf("%s : %s\n", s, b);
printf("%s", b);
}

Concatenating an int to a string or converting in C

Im looking for a 6 digit random number on the end of foo-, I have been trying for a few hours now with no success. only error messages
note: expected 'char *' but argument is of type 'int'
Ive tried to convert the int to char but it just doesn't like it, My code is below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char* concat(char *s1, char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
//in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
int main ()
{
srand(time(NULL));
int r = rand();
printf(concat("foo-", r));
return 0;
}
You could do this
printf("foo-%d", r);
or
char buffer[10];
sprintf(buffer, "%d", r);
char *c = concat("foo-", r);
printf("%s", c);
free(c);
This will use your function. Please read the manual pages for sprintf and printf
for example:
srand(time(NULL));
int r = rand();
char* str = (char*)malloc(sizeof(char)*20);
snprintf(str, 7, "%d", r);
if (strlen(str) < 6) { /* if r had less than 6 digits */
sprintf(str, "%06d", r);
}
char* s = concat("foo-", str);
printf("%s",s);
free(str);
free(s);
return 0;
from http://joequery.me/code/snprintf-c/ :
int snprintf(char *str, size_t size, const char *format, ...);
str is the buffer where printf output will be redirected to. size is the maximum number of bytes(characters) that will be written to the
buffer, including the terminating null character that snprintf
automatically places for you. The format and the optional ...
arguments are just the string formats like "%d", myint as seen in
printf.
so, in order to get a 6 digit number converted, you specify in snprintf() the size argument to 7 (you include a null character).
sprintf() function sends formatted output to a string pointed to by the first argument (in our case this is str). %06d format provides that to str at least 6 digits will be sent.
CONCLUSION
you want to convert a 6 digit number to a char array. if the number had at least 6 digits, with snprintf() you will get the first 6 digits of the number that was converted. if it has less than 6 digits, the sprintf() will add zeroes at the beginning until there are 6 digits. so, if r = 101; the result would be 000101.
note that with your usage of concat function:
printf(concat("foo-",r));
compiler warns about (gcc in my case):
warning: format not a string literal and no format arguments
[-Wformat-security]
printf() function needs to know the format of the string argument that is passed. there's a nice answer about it right here : warning: format not a string literal and no format arguments
In the example I'm using sprintf to convert int to char[]. Also I'm using modulo operation to ensure the result will have no more than 6 digits. The %06d argument for sprintf will ensure that the result will have no less than 6 digits.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
char buf[7] = { 0 };
int r;
srand(time(NULL));
r = rand() % 1000000;
sprintf(buf, "%06d", r);
printf("foo-%s\n", buf);
return 0;
}
Your problem occurs when you attempt to call concat with the int value r as the second argument. Notice your definition of concat:
char* concat(char *s1, char *s2);
The second argument is char *s2. In your program you attempt to call it with:
int r = rand();
printf(concat("foo-", r));
r is an integer. Try this to correct the problem:
int main ()
{
srand(time(NULL));
int r = rand();
char str[] = "bar";
printf(concat("foo-", str));
return 0;
}

Resources