Suppose you have a string which is NOT null terminated and you know its exact size, so how can you print that string with printf in C? I recall such a method but I can not find out now...
There is a possibility with printf, it goes like this:
printf("%.*s", stringLength, pointerToString);
No need to copy anything, no need to modify the original string or buffer.
Here is an explanation of how %.*s works, and where it's specified.
The conversion specifications in a printf template string have the general form:
% [ param-no $] flags width [ . precision ] type conversion
or
% [ param-no $] flags width . * [ param-no $] type conversion
The second form is for getting the precision from the argument list:
You can also specify a precision of ‘*’. This means that the next argument in the argument list (before the actual value to be printed) is used as the precision. The value must be an int, and is ignored if it is negative.
— Output conversion syntax in the glibc manual
For %s string formatting, precision has a special meaning:
A precision can be specified to indicate the maximum number of characters to write; otherwise characters in the string up to but not including the terminating null character are written to the output stream.
— Other output conversions in the glibc manual
Other useful variants:
"%*.*s", maxlen, maxlen, val will right-justify, inserting spaces before;
"%-*.*s", maxlen, maxlen, val will left-justify.
You can use an fwrite() to stdout!
fwrite(your_string, sizeof(char), number_of_chars, stdout);
This way you will output the first chars (number defined in number_of_chars variable ) to a file, in this case to stdout (the standard output, your screen)!
printf("%.*s", length, string) will NOT work.
This means to print UP TO length bytes OR a null byte, whichever comes first. If your non-null-terminated array-of-char contains null bytes BEFORE the length, printf will stop on those, and not continue.
printf("%.5s", pointerToNonNullTerminatedString);
The string length will be 5.
#include<string.h>
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
int i;
for(i=0;i<n;i++)
{
printf("%c",str[i]);
}
return 0;
}
I edited the code,heres another way:
#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/
return 0;
}
Related
I'm trying to find the first string (max 4 characters) in a comma-separated list of strings inside a C char-array.
I'm trying to achieve this by using sscanf_s (under Windows) and the format-control string %[^,]:
char mystring[] = "STR1,STR2";
char temp[5];
if (sscanf_s(mystring, "%[^,]", temp, 5) != 0) {
if (strcmp(temp, "STR1") == 0) { return 0; }
else if (strcmp(temp, "STR2") == 0) { return 1; }
else { return -1; }
}
After calling sscanf_s the content of temp is not STR1 but \0TR1 (\0 being the ASCII-interpretation of 0). And the value -1 is returned.
Why do I get that behavior and how do I fix my code to get the right result (return of 0)?
EDIT: changed char mystring to mystring[] (I should have made sure I typed it correcly here)
There are multiple problems in your code:
mystring is defined as a char, not a string pointer.
the argument 5 following temp in sscanf_s() should have type rsize_t, which is the same as size_t. You should specify it as sizeof(temp).
you should specify the maximum number of characters to store into the destination array in the format string, to avoid the counter-intuitive behavior of sscanf_s in case of overflow.
sscanf_s returns 1 if it can convert and store the string. Testing != 0 will also accept EOF which is an input failure, for which the contents of temp is indeterminate.
Here is a modified version:
const char *mystring = "STR1,STR2";
char temp[5];
if (sscanf_s(mystring, "%4[^,]", temp, sizeof temp) == 1) {
if (strcmp(temp, "STR1") == 0) {
return 0;
} else
if (strcmp(temp, "STR2") == 0) {
return 1;
} else {
return -1;
}
}
UPDATE: The OP uses Microsoft Visual Studio, which seems to have a non-conforming implementation of the so-called secure stream functions. Here is a citation from their documentation page:
The sscanf_s function reads data from buffer into the location that's given by each argument. The arguments after the format string specify pointers to variables that have a type that corresponds to a type specifier in format. Unlike the less secure version sscanf, a buffer size parameter is required when you use the type field characters c, C, s, S, or string control sets that are enclosed in []. The buffer size in characters must be supplied as an additional parameter immediately after each buffer parameter that requires it. For example, if you are reading into a string, the buffer size for that string is passed as follows:
wchar_t ws[10];
swscanf_s(in_str, L"%9s", ws, (unsigned)_countof(ws)); // buffer size is 10, width specification is 9
The buffer size includes the terminating null. A width specification field may be used to ensure that the token that's read in will fit into the buffer. If no width specification field is used, and the token read in is too big to fit in the buffer, nothing is written to that buffer.
In the case of characters, a single character may be read as follows:
wchar_t wc;
swscanf_s(in_str, L"%c", &wc, 1);
This example reads a single character from the input string and then stores it in a wide-character buffer. When you read multiple characters for non-null terminated strings, unsigned integers are used as the width specification and the buffer size.
char c[4];
sscanf_s(input, "%4c", &c, (unsigned)_countof(c)); // not null terminated
This example reads a single character from the input string and then stores it in a wide-character buffer. When you read multiple characters for non-null terminated strings, unsigned integers are used as the width specification and the buffer size.
char c[4];
sscanf_s(input, "%4c", &c, (unsigned)_countof(c)); // not null terminated
This specification is incompatible with the C Standard, that specifies the type of the width arguments to be rsize_t and type rsize_t to be the same type as size_t.
As a conclusion, for improved portability, one should avoid using these secure functions and use the standard functions correctly, with the length prefix to prevent buffer overruns.
You can prevent the Visual Studio warning about deprecation of sscanf by inserting this definition before including <stdio.h>:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS // let me use standard functions
#endif
edited per the comment from chqrlie
regarding:
if(sscanf_s(mystring, "%[^,]",temp, 5) != 0){
The input format conversion specifier: %[..] always appends a NUL byte to the end of the input. So the input format conversion specifier should be: "%4[^,]" The result after the correction is:
if(sscanf_s(mystring, "%4[^,]",temp, 5) != 0){
also, no matter how many times this code snippet is executed, the returned value wnce the other problems are corrected will ALWAYS be STR1
regarding the statement;
char mystring = "STR1,STR2";
This is not a valid statement. Suggest:
char *mystring = "STR1,STR2"; // notice the '*'
--or--
char mystring[] = "STR1,STR2"; // notice the '[]'
I'm teaching myself programming. I read that a string stored in an array of characters can be indexed to extract the nth character.
However, I've been trying to solve this for hours: I realized trying to solve an exercise that I can only access the first character of the array myarray[0]; whereas the rest of index (1,2,3...) values will return nothing. However, if I use the puts function it does return the whole string. Curious thing: strlen is returning the length of my array +1.
example:
int main (void)
{
char myarray[1000]={0};
int i;
fgets(myarray,1000,stdin);
for(i=0;i<strlen(myarray);i++)
printf("myarray[%d]:%c\n",i,myarray[i]);
printf("\n");
printf("strlen:%d\n",strlen(myarray));
puts(myarray);
return 0;
}
input:
6536
output:
strlen:5
myarray[0]:6
myarray[1]:
myarray[2]:
myarray[3]:
myarray[4]:
6536
You are getting this result most probably because of undefined behavior of your program. You are using wrong format specifier to print a size_t type (strlenreturn size_t type). Change the format specifier to %zu.
Also note that in for loop you need to declare i as size_t type.
Here is the fixed code: http://ideone.com/0sMadV
fgets writes a newline character \n into the buffer to represent newlines in the input stream. Thus strlen returns 5.
The actual output is :
6536
myarray[0]:6
myarray[1]:5
myarray[2]:3
myarray[3]:6
myarray[4]:
strlen:5
6536
As you can see, myarray[4] stores the newline (due to fgets). Also, it would be better to calculate strlen once by placing it above the loop, instead of in every iteration.
From here:
char *fgets(char *restrict s, int n, FILE *restrict stream);
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a is read and
transferred to s, or an end-of-file condition is encountered. The
string is then terminated with a null byte.
A simple way is to for strlen(var)-1. Another way is to remove the newline with null terminating character:
if (myarray[length - 1] == '\n')
myarray[length - 1] = '\0';
where length = strlen(myarray);
The strlen counts the '\n' at the end of the string. You can "fix" it with strtok:
strtok(myarray, "\n");
I have read about %02x format specifiers but when it comes to an argument of type char array, I am unable to understand the output of the following piece of code:
int main() {
// your code goes here
char str[6] = "abcde";
char t[3];
snprintf(t,3,"%02x",str);
printf("\t%s",t);
return 0;
}
Output:
bf
How str is being parsed under this format specifier, is a point of concern. What I feel, the output should have been "ab" (without quotes).
The point to make here is that if you are printing anything using %02x then you should be using it for each byte. It is common when printing a hash digest to declare a field of size twice the digest size (+1 for \0 if a string) and then populate it with repetitive sprintf() calls.
So one needs to loop through the bytes.
Have a look at the CPlusPlus entry on printf.
I think the format specifier you are looking for is %2.2s, which limits the minimum and maximum number of characters printed to 2, and it will print a string, rather than the value of your pointer.
main(){
printf("%2.2s","abcde");
return 0;
}
This will print "ab" (without the quotes). The same format rules apply to the entire printf family, including snprintf.
%02x is a format specifier that tells the parser that your value is a number, you want it to be printed in base 16, you want there to be at least 2 characters printed, and that any padding it applies should be full of zeroes, rather than spaces. You need to use some version of %s for printing strings.
You should read your source carefully. They might use something like this:
int main() {
char str[6] = "abcde";
char t[2*6] = { 0 };
int i;
for (i = 0; i <= 5; ++i)
{
snprintf(t+2*i, sizeof(t)-2*(i), "%02x", str[i]);
}
printf("\t%s",t);
return 0;
}
The %02x is used to convert one character to a hexadecimal string. Therefore you need to access individual charaters of str. You can build a line as my code shows or you can output each converted string as your fragment shows. But then it doesn't make sense to use the temporary variable t.
Edit: Fixed code.
#include<stdio.h>
int main()
{
char str[50]={'\0'};
scanf("%[A-Z]s",str);
printf("%s",str);
return 0;
}
1)
Input:
helloWORLD
output:
2)
Input:
HELLoworlD
output:
HELL
In output 1, i expected the output as "WORLD" but it didnt give any outout.
From output 2, i understood that this is working only if the first few characters are in upper case.
Can you please explain how it actually works?
Interpretation of scansets
When it is given helloWORLD, the conversion specification %[A-Z] fails immediately because the h is not an upper-case letter. Therefore, scanf() returns 0, indicating that it did not successfully convert anything. If you tested the return value, you'd know that.
When it is given HELLoworlD, the scanset matches the HELL and stops at the first o. The format string also attempts to match a literal s, but there's no way for scanf() to report that it fails to match that after matching HELL.
Buffer overflow
Note that %[A-Z] is in general dangerous (as is %s) because there is no constraint on the number of characters read. If you have:
char str[50];
then you should use:
if (scanf("%49[A-Z]", str) != 1)
...some problem in the scan...
Also note that there is a 'difference by one' between the declared length of str and the number in the format string. This is awkward; there's no way to provide that number as an argument to scanf() separate from the format string (unlike printf()), so you may end up creating the format string on the fly:
int scan_upper(char *buffer, size_t buflen)
{
char format[16];
if (buflen < 2)
return EOF; // Or other error indication
snprintf(format, sizeof(format), "%%%zu[A-Z]", buflen-1); // Check this too!?
return scanf(format, buffer);
}
When you do
scanf("%[A-Z]s",str);
It takes input as long as you enter upper-case letters.
And since you set all the array to '\0', printf() will stop printing when it meets one.
Therefore, the first input is blank, and the second is printing until the end of the upper-case string.
The man page states that the signature of sscanf is
sscanf(const char *restrict s, const char *restrict format, ...);
I have seen an answer on SO where a function in which sscanf is used like this to check if an input was an integer.
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
Looking at !s[n] it seems to suggest that we check if sscanf scanned the character sequence until the termination character \0. So I assume n stands for the index where sscanf will be in the string s when the function ends.
But what about the variable i? What does it mean?
Edit:
To be more explicit: I see the signature of sscanf wants a pointer of type char * as first parameter. A format specifier as seconf parameter so it knows how to parse the character sequence and as much variables as conversion specifiers as next parameters. I understand now that i is for holding the parsed integer.
Since there is only one format specifier, I tried to deduce the function of n.
Is my assumption above for n correct?
Looks like the op has his answer already, but since I bothered to look this up for myself and run the code...
From "C The Pocket Reference" (2nd Ed by Herbert Shildt) scanf() section:
%n Receives an integer of value equal to the number of characters read so far
and for the return value:
The scanf() function returns a number equal to the number of the number of fields
that were successfully assigned values
The sscanf() function works the same, it just takes it's input from the supplied buffer argument ( s in this case ). The "== 1" test makes sure that only one integer was parsed and the !s[n] makes sure the input buffer is well terminated after the parsed integer and/or that there's really only one integer in the string.
Running this code, an s value like "32" gives a "true" value ( we don't have bool defined as a type on our system ) but s as "3 2" gives a "false" value because s[n] in that case is "2" and n has the value 2 ( "3 " is parsed to create the int in that case ). If s is " 3 " this function will still return true as all that white space is ingored and n has the value of 3.
Another example input, "3m", gives a "false" value as you'd expect.
Verbatim from sscanf()'s man page:
Conversions
[...]
n
Nothing is expected; instead, the number of characters
consumed thus far from the input is stored through the next pointer,
which must be a pointer to int. This is not a
conversion, although it can be suppressed with the * assignment-suppression character. The C
standard says: "Execution of
a %n directive does not increment the assignment count returned at the completion of
execution" but the Corrigendum seems to contradict this. Probably it is wise not
to make any assumptions on the effect of %n conversions on the return value.
I would like to point out that the original code is buggy:
bool is_int(char const* s) {
int n;
int i;
return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}
I will explain why. And I will interpret the sscanf format string.
First, buggy:
Given input "1", which is the integer one, sscanf will store 1 into i. Then, since there is no white space after, sscanf will not touch n. And n is uninitialized. Because sscanf set i to 1, the value returned by sscanf will be 1, meaning 1 field scanned. Since sscanf returns 1, the part of the expression
sscanf(s, "%d %n", &i, &n) == 1
will be true. Therefore the other part of the && expression will execute. And s[n] will access some random place in memory because n is uninitialized.
Interpreting the format:
"%d %n"
Attempts to scan a number which may be a decimal number or an integer or a scientific notation number. The number is an integer, it must be followed by at least one white space. White space would be a space, \n, \t, and certain other non-printable characters. Only if it is followed by white space will it set n to the number of characters scanned to that point, including the white space.
This code might be what is intended:
static bool is_int(char const* s)
{
int i;
int fld;
return (fld = sscanf(s, "%i", &i)) == 1;
}
int main(int argc, char * argv[])
{
bool ans = false;
ans = is_int("1");
ans = is_int("m");
return 0;
}
This code is based on, if s is an integer, then sscanf will scan it and fld will be exactly one. If s is not an integer, then fld will be zero or -1. Zero if something else is there, like a word; and -1 if nothing is there but an empty string.
variable i there means until it has read an integer vaalue.
what are you trying to ask though? Its not too clear! the code will (try to ) read an integer from the string into 'i'