Whenever I need to assign to a string and I have some word (called variedinput) that is assigned via standard input, socket, etc, I do something like
char buffer[50];
strcpy(buffer, "The ");
strcat(buffer, variedinput);
strcat(buffer, " jumped over the fence.");
Is there some other function that allows me to do something like the following?
function(buffer, "The %s jumped over the fence.", variedinput)
Yes, it is called spnrintf. I your code:
snprintf(buffer, sizeof buffer, "The %s jumped over the fence", variedinput);
The rules for the format string and later arguments are the same as for printf. Of course, you must make sure variedinput actually points to a string in this example.
sprintf(buffer,"",...)?
Write formatted data to string.
http://www.cplusplus.com/reference/cstdio/sprintf/?kw=sprintf
Related
I have something in my code as below:
This is code for creating a DEVICE in linux under /dev
#define PRINTER_STR "printer_"
char str[32];
snprintf(str, sizeof(str), PRINTER_STR "%s%s", dev->type, "%u");
device_create(mycan_drv.class, parent,
MKDEV(dev->nMajor, dev->nMinor),
dev, str, dev->nMinor);
4th parameter to snprintf which is dev->type is assigned with strings like epson,hp,canon.
Output achieved is something like this :
printer_epson32,printer_hp33,printer_canon34
In the above output strings, I couldnt understand how the numbers like 32,33,34 are built.
I can understand this is because of the 5th parameter "%u" passed to snprintf. But how ?
All the references i got are with max 3 or 4 parameters of snprintf.
Kindly help.
char str[32];
dev->type = "epson";
snprintf(str, sizeof(str), "printer_" "%s%s", dev->type, "%u");
results in:
str = "printer_epson%u".
Then code does:
device_create(..., str, dev->nMinor);
which is really:
device_create(..., "printer_epson%u", dev->nMinor);
and then inside device_create a *printf like function is once again called and it writes dev->nMinor in place of %u. So, like, it's not snprintf that writes the number, the number is written inside device_create. snprintf is used to create the formatting string for device_create and device_create writes that number.
Side note: The "%s%s", dev->type, "%u") looks strange, it could have been just "%s%%u", dev->type);. And anyway for all that it could have just been device_create(...., "%s%u", dev->type, dev->nMinor).
Simpler would be:
snprintf(str, sizeof(str), PRINTER_STR "%s%%u", dev->type);
Since %u is a fixed string, it could be just included in the format. The % needs to be escaped to avoid being interpreted by snprintf.
Hello I'm quite new to C and in a nutshell I was doing the following as part of my assignment in class:
foo (char *var) {
printf(var);
}
I was told that this is bad practice and insecure but did not get much detailed information on this by my tutor. I assume that if the string value of var is controllable by the user it may be used to perform a bufferoverflow? How would I properly harden this code? Do I have to limit the str length or something?
Cheers & Thanks!
You should use:
printf("%s", var);
instead. The way you have it, I could enter %s as my input, and printf would read a random piece of memory as it looked for a string to print. That can cause any amount of unexpected behaviour.
This is UNSAFE because it could lead to a Format String Attack
Well, the first argument of printf is a format string. So the caller of your function could pass:
foo("%d")
and then printf would look for an integer which isn't there, and cause undefined behaviour. One possible fix would be for your function to call:
printf("%s", var);
which would have printf interpret var as a regular string (rather than a format).
Printf has the following signature:
int printf(
const char *format [,
argument]...
);
If the user inputs format characters for example %s all kinds of bad things will happen.
Use puts if you just want to output the string.
I have something like this
char string[]="My name is %s";
printf("%s",string,"Tom");
I expect the output to be My name is Tom but I am getting My name is %s
I tried escaping the % character, but it dint work.
What's going wrong here? How shall I have a %s inside a %s?
Try something like this
printf(string,"Tom");
The problem with your method is this -
As soon as printf sees %s format specifier in your format string, it assumes that the next argument in list is a string pointed to by a character pointer, retrieves it and prints it in place of %s. Now, printf doesn't do a recursive replacement and hence
%s inside your string remains as it is and "Tom" is now an extra argument which is just discarded.
There is only one expansion during printf; that means any strings passed to printf except the format strings will be printed verbatim (if at all). That is actually a good thing, because otherwise, it leaves a huge security hole.
The security risk relates to the fact that the format string and the parameter list have to correspond. That means, if an unwanted % makes it to the format string, you will get in trouble:
char ch[50];
fgets(ch, 50, stdin);
printf(ch);
If the user supplies eg. %p %p %p %p, he will be reading data stored on the stack (like the return address and so on), if he supplies %s %s %s, he'll likely crash the program. If he supplies %n, he'll overwrite some data on the stack.
That said, you can just compute the format string if you want:
char ch[50];
char format_prototype[]="My name is %s";
snprintf(ch, 49, "%s", format_prototype);
ch[49]=0;
printf(ch, "Tom");
printf(string, "Tom") maybe?
The problem is with printf("%s",string,"Tom");
line
You should use
char string[]="My name is %s";
printf(string,"Tom");
here you will get the output as
My name is Tom
The first parameter to printf is the format string. The rest are all parameters which will be formatted according to the format string. The format strings do not nest in any way. In other words, even if a string to be formatted happens to contain formatting instruction, it is simply printed and not interpreted as another format string.
If you want to have that kind of formatting indirection, you would have to first generate a new format string (sprintf is useful for that):
char string[] = "My name is %s";
char format[100];
sprintf(format, "%s", string);
and then use the newly generated format string:
printf(format, "Tom");
Let's say that I expect a list of items from the standard input which are separated buy commas, like this:
item1, item2, item3,...,itemn
and I also want to permit the user to emit white-spaces between items and commas, so this kind of input is legal in my program:
item1,item2,item3,...,itemn
If I use scanf like this:
scanf("%s,%s,%s,%s,...,%s", s1, s2, s3, s4,...,sn);
it will fail when there are no white-spaces (I tested it) because it will refer to the whole input as one string. So how can I solve this problem only with C standard library functions?
The quick answer is never, ever use scanf to read user input. It is intended for reading strictly formatted input from files, and even then isn't much good. At the least, you should be reading entire lines and then parsing them with sscanf(), which gives you some chance to correct errors. at best you should be writing your own parsing functions
If you are actually using C++, investigate the use of the c++ string and stream classes, which are much more powerful and safe.
You could have a look at strtok. First read the line into a buffer, then tokenize:
const int BUFFERSIZE = 32768;
char buffer[BUFFERSIZE];
fgets(buffer, sizeof(buffer), stdin);
const char* delimiters = " ,\n";
char* p = strtok(buffer, delimiters);
while (p != NULL)
{
printf("%s\n", pch);
p = strtok(NULL, delimiters);
}
However, with strtok you'll need to be aware of the potential issues related to reentrance.
I guess it is better to write your own parsing function for this. But if you still prefer scanf despite of its pitfalls, you can do some workaround, just substitute %s with %[^, \t\r\n].
The problem that %s match sequence of non white space characters, so it swallows comma too. So if you replace %s with %[^, \t\r\n] it will work almost the same (difference is that %s uses isspace(3) to match space characters but in this case you explicitly specify which space characters to match and this list probably not the same as for isspace).
Please note, if you want to allow spaces before and after comma you must add white space to your format string. Format string "%[^, \t\r\n] , %[^, \t\r\n]" matches strings like "hello,world", "hello, world", "hello , world".
Normally you can print a string in C like this..
printf("No record with name %s found\n", inputString);
But I wanted to make a string out of it, how I can do it? I am looking for something like this..
char *str = ("No record with name %s found\n", inputString);
I hope it is clear what I am looking for...
One option would be to use sprintf, which works just like printf but takes as its first parameter a pointer to the buffer into which it should place the resulting string.
It is preferable to use snprintf, which takes an additional parameter containing the length of the buffer to prevent buffer overruns. For example:
char buffer[1024];
snprintf(buffer, 1024, "No record with name %s found\n", inputString);
You're looking for the sprintf family of functions. Their general format is:
char output[80];
sprintf(output, "No record with name %s found\n", inputString);
However, sprintf by itself is extremely dangerous. It is prone to something called buffer overruns. What this means it that sprintf has no idea how big the output string you provide it is, so it will willingly write more data to it than is available. For example, this will compile cleanly, but will overwrite valid memory—and there is no way to let sprintf know that it's doing anything wrong:
char output[10];
sprintf(output, "%s", "This string is too long");
The solution is to use a function as snprintf, which takes a length parameter:
char output[10];
snprintf(output, sizeof output, "%s", "This string is too long, but will be truncated");
or, if you're on a Windows system, to use the _sntprintf variants and friends, which protect against overflowing of either the input or output strings.
Since this is homework (thanks for tagging it as such) I'll suggest you to look closely at the ...printf() family of functions.
I'm sure you'll find the solution :)
Look into sprintf (see below).
int n = sprintf(str, "No record with name %s found\n", inputString);
Use
sprintf(str, "No record with name %s found\n", inputString);