How can I print a non-null-terminated string using printf, assuming that I know the length of the string at runtime?
printf("%.*s", length, string);
Use together with other args:
printf("integer=%d, string=%.*s, number=%f", integer, length, string, number);
// ^^^^ ^^^^^^^^^^^^^^
In C you could specify the maximum length to output with the %.123s format. This means the output length is at most 123 chars. The 123 could be replaced by *, so that the length will be taken from the argument of printf instead of hard-coded.
Note that this assumes the string does not contain any interior null bytes (\0), as %.123s only constrains the maximum length not the exact length, and strings are still treated as null-terminated.
If you want to print a non-null-terminated string with interior null, you cannot use a single printf. Use fwrite instead:
fwrite(string, 1, length, stdout);
See #M.S.Dousti's answer for detailed explanation.
The answer provided by #KennyTM is great, but with a subtlety.
In general, if the string is non-null "terminated", but has a null character in the middle, printf("%.*s", length, string); does not work as expected. This is because the %.*s format string asks printf to print a maximum of length characters, not exactly length characters.
I'd rather use the more general solution pointed out by #William Pursell in a comment under the OP:
fwrite(string, sizeof(char), length, stdout);
Here's a sample code:
#include <stdio.h>
int main(void) {
size_t length = 5;
char string[length];
string[0] = 'A';
string[1] = 'B';
string[2] = 0; // null character in the middle
string[3] = 'C';
string[4] = 'D';
printf("With printf: %.*s\n", length, string);
printf("With fwrite: ");
fwrite(string, sizeof(char), length, stdout);
printf("\n");
return 0;
}
Output:
With printf: AB
With fwrite: AB CD
Related
I'm trying to write a program that does the following:
Enter a word: supercalifragilisticoespialidoso
The word's length is: 32.
Enter a smaller number than the length: 23
The word cut on letter 23 is: supercalifragilisticoes.
For that I'm doing:
#include <stdio.h>
#include<string.h>
#define DIM 99
int main() {
char name[DIM], name2[DIM];
int length, length2;
printf("Enter a word: ");
scanf("%s", name);
length = strlen(name);
printf("The word's length is: %d\n", length);
printf("Enter a smaller number than the length: ");
scanf("%d", &length2);
name2 = name[length2];
printf("The word cut on the letter %d is: %c", length2, name2);
return 0;
}
But I get
main.c:16:11: error: assignment to expression with array type
The problem is in the line name2 = name[length2], that's the way I found to create the new smaller word, but it's not right.
Could someone please help?
The mistake is in the line
name2 = name[length2];
You're trying to assign a character (the one of index length2 inside name) to an array (name2).
What you actually want to do is this:
strncpy(name2, name, length2);
name2[length2] = '\0';
This copies the first length2 bytes of name into name2 and adds a terminating null character for safety (strncpy doesn't do it if all of the bytes are written).
If you don't intend to use name again, you could as well remove name2 altogether and add a null character to name:
name[length2] = '\0';
You're also printing a string with a %c format specifier on the last printf call. You should use %s instead.
Other answers have suggested how you might make a copy of the initial substring of your input or how to modify the input string in place. Those are perfectly good approaches, and both have plenty of uses in real-world programs.
However, if all your program needs to do is print the wanted substring then there is no need to do any string manipulation at all. printf can do the job by itself. Given the variables as you declared them and this code ...
scanf("%s", name);
length = strlen(name);
printf("The word's length is: %d\n", length);
printf("Enter a smaller number than the length: ");
scanf("%d", &length2);
... you can use a printf format to print name into a bounded-length field whose length is given by another printf argument:
printf("%.*s\n", length2, name);
That also adds a newline after, which is usually what one wants, but you can leave that off if you prefer.
The .* in the formatting directive indicates that a "precision" is being specified for the field via a printf argument. Other variations can express a fixed precision directly in the format. The significance of a precision depends somewhat on the directive type, but for s directives it is the maximum number of characters to be printed from the corresponding string argument.
There are two main errors in your code, and a couple of other minor points.
First, you can't directly assign arrays (be they character strings or any other array type) in C; for nul-terminated char arrays (strings), you can copy one to another using the strcpy function, or copy part of one to another using strncpy (which is what you want in your case).
Second, you can't print a string using the %c format specifier – you need %s for those.
And, a less serious issue (but one to avoid, if you want to be a good programmer) is that functions that work with string lengths (like strlen and strncpy) generally use size_t types, rather than int; and these require using the %zu format specifier, in place of %d.
Here's a version of your code that does what you want:
#include <stdio.h>
#include<string.h>
#define DIM 99
int main()
{
char name[DIM], name2[DIM] = { 0 }; // Fill with zeros to start, so we will have a nul terminator
size_t length, length2; // Strictly, use "size_t" for "strlen" and "strncpy"
printf("Enter a word: ");
scanf("%s", name);
length = strlen(name);
printf("The word's length is: %zu\n", length); // Use "%zu" for the "size_t" type
printf("Enter a smaller number than the length: ");
scanf("%zu", &length2); //Again, "%zu" for "size_t"
strncpy(name2, name, length2); // Use this function to copy a substring!
printf("The word cut on the letter %zu is: %s", length2, name2);// Note that you need "%s" to print a string
return 0;
}
There are some other 'safety measures' that you can add to your code, to prevent buffer overruns and other faults. One would be to limit the initial string input to at most DIM - 1 characters; this would be trivial if you had a hard-coded value of 99 in place of DIM, because then you could use a call like the following:
scanf("%98s", name); // Read at most 98 characters (leaving space for the nul-terminator)
However, the macro DIM cannot be used inside the quoted format string. Instead, you can write its value (minus 1) into a separate string and use that as the format argument to scanf; so, we replace our initial scanf call, like so:
// scanf("%s", name); // This has the potential to overrun the "name" array!
char fmt[8];
sprintf(fmt, "%%%ds", DIM - 1); // Write "%98s" into the "fmt" string ...
scanf(fmt, name); // ...and use that for the "scanf" format
(Note that some compilers will warn about not using a string literal for the format argument, and some programmers may not 'approve' of doing so; however, it is perfectly legal C and, IMHO, a valid use of the scanf function.)
The assignment:
name2 = name[length2];
does not have the semantics you appear to have assumed. Rather name2 is an array while name[length2] is a a single character at the index length2 of the array name.
In any event arrays are not first-class data types in C and you cannot assign one array to another (as it appears you were perhaps intending) let alone assigning a char for an array.
Here you might explicitly strncpy() to copy the sub-string, but in this case that is perhaps unnecessary. You can simply remove the name2 array and:
printf( "The word cut on the letter %d is: ", length2 ) ;
for( int i = 0; i < length && i < length2; i++ )
{
putchar( name[i] ) ;
}
If you truly need to store the sub-string rather then simply outputting it then:
int i = 0 ;
for( i = 0; i < length && i < length2; i++ )
{
name2[i] = name[i] ;
}
name2[i] = '\0' ;
Both have the advantage of behaving deterministically if length2 were less than zero or greater than length which you fail to check.
Using strncpy():
int len = (length2 < 0 || length2 > length) ?
length :
length2 ;
strncpy( name2, name, len ) ;
name2[len] = '\0' ;
Of course all those length checks are largely defeated by the lack of safety in acquiring name in the manner you have in the first instance. Consider using fgets() instead, or even getchar() in a loop.
I'm trying to use sprintf() to put a string "inside itself", so I can change it to have an integer prefix. I was testing this on a character array of length 12 with "Hello World" inside it already.
The basic premise is that I want a prefix that denotes the amount of words within a string. So I copy 11 characters into a character array of length 12.
Then I try to put the integer followed by the string itself by using "%i%s" in the function. To get past the integer (I don't just use myStr as the argument for %s), I make sure to use myStr + snprintf(NULL, 0, "%i", wordCount), which should be myStr + characters taken up by the integer.
The problem is that I'm having is that it eats the 'H' when I do this and prints "2ello World" instead of having the '2' right beside the "Hello World"
So far I've tried different options for getting "past the integer" in the string when I try to copy it inside itself, but nothing really seems to be the right case, as it either comes out as an empty string or just the integer prefix itself '222222222222' copied throughout the entire array.
int main() {
char myStr[12];
strcpy(myStr, "Hello World");//11 Characters in length
int wordCount = 2;
//Put the integer wordCount followed by the string myStr (past whatever amount of characters the integer would take up) inside of myStr
sprintf(myStr, "%i%s", wordCount, myStr + snprintf(NULL, 0, "%i", wordCount));
printf("\nChanged myStr '%s'\n", myStr);//Prints '2ello World'
return 0;
}
First, to insert a one-digit prefix into a string “Hello World”, you need a buffer of 13 characters—one for the prefix, eleven for the characters in “Hello World”, and one for the terminating null character.
Second, you should not pass a buffer to snprintf as both the output buffer and an input string. Its behavior is not defined by the C standard when objects passed to it overlap.
Below is a program that shows you how to insert a prefix by moving the string with memmove. This is largely tutorial, as it is not generally a good way to manipulate strings. For short strings, where space is not an issue, most programmers would simply print the desired string into a temporary buffer, avoiding overlap issues.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Insert a decimal numeral for Prefix into the beginning of String.
Length specifies the total number of bytes available at String.
*/
static void InsertPrefix(char *String, size_t Length, int Prefix)
{
// Find out how many characters the numeral needs.
int CharactersNeeded = snprintf(NULL, 0, "%i", Prefix);
// Find the current string length.
size_t Current = strlen(String);
/* Test whether there is enough space for the prefix, the current string,
and the terminating null character.
*/
if (Length < CharactersNeeded + Current + 1)
{
fprintf(stderr,
"Error, not enough space in string to insert prefix.\n");
exit(EXIT_FAILURE);
}
// Move the string to make room for the prefix.
memmove(String + CharactersNeeded, String, Current + 1);
/* Remember the first character, because snprintf will overwrite it with a
null character.
*/
char Temporary = String[0];
// Write the prefix, including a terminating null character.
snprintf(String, CharactersNeeded + 1, "%i", Prefix);
// Restore the first character of the original string.
String[CharactersNeeded] = Temporary;
}
int main(void)
{
char MyString[13] = "Hello World";
InsertPrefix(MyString, sizeof MyString, 2);
printf("Result = \"%s\".\n", MyString);
}
The best way to deal with this is to create another buffer to output to, and then if you really need to copy back to the source string then copy it back once the new copy is created.
There are other ways to "optimise" this if you really needed to, like putting your source string into the middle of the buffer so you can append and change the string pointer for the source (not recommended, unless you are running on an embedded target with limited RAM and the buffer is huge). Remember code is for people to read so best to keep it clean and easy to read.
#define MAX_BUFFER_SIZE 128
int main() {
char srcString[MAX_BUFFER_SIZE];
char destString[MAX_BUFFER_SIZE];
strncpy(srcString, "Hello World", MAX_BUFFER_SIZE);
int wordCount = 2;
snprintf(destString, MAX_BUFFER_SIZE, "%i%s", wordCount, srcString);
printf("Changed string '%s'\n", destString);
// Or if you really want the string put back into srcString then:
strncpy(srcString, destString, MAX_BUFFER_SIZE);
printf("Changed string in source '%s'\n", srcString);
return 0;
}
Notes:
To be safer protecting overflows in memory you should use strncpy and snprintf.
I am trying to make function that compares all the letters from alphabet to string I insert, and prints letters I didn't use. But when I print those letters it goes over and gives me random symbols at end. Here is link to function, how I call the function and result: http://imgur.com/WJRZvqD,U6Z861j,PXCQa4V#0
Here is code: (http://pastebin.com/fCyzFVAF)
void getAvailableLetters(char lettersGuessed[], char availableLetters[])
{
char alphabet[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int LG,LG2,LA=0;
for (LG=0;LG<=strlen(alphabet)-1;LG++)
{
for(LG2=0;LG2<=strlen(lettersGuessed)-1;LG2++)
{
if (alphabet[LG]==lettersGuessed[LG2])
{
break;
}
else if(alphabet[LG]!=lettersGuessed[LG2] &&LG2==strlen(lettersGuessed)-1)
{
availableLetters[LA]=alphabet[LG];
LA++;
}
}
}
}
Here is program to call the function:
#include <stdio.h>
#include <string.h>
#include "hangman.c"
int main()
{
int i = 0;
char result[30];
char text[30];
scanf("%s", text);
while(i != strlen(text))
{
i++;
}
getAvailableLetters(text, result);
printf("%s\n", result);
printf ("%d", i);
printf ("\n");
}
Here is result when I typed in abcd: efghijklmnopqrstuvwxyzUw▒ˉ
If you want to print result as a string, you need to include a terminating null at the end of it (that's how printf knows when to stop).
for %s printf stops printing when it reaches a null character '\0', because %s expects the string to be null terminated, but result not null terminated and that's why you get random symbols at the end
just add availableLetters[LA] = '\0' at the last line in the function getAvailableLetters
http://pastebin.com/fCyzFVAF
Make sure your string is NULL-terminated (e.g. has a '\0' character at the end). And that also implies ensuring the buffer that holds the string is large enough to contain the null terminator.
Sometimes one thinks they've got a null terminated string but the string has overflowed the boundary in memory and truncated away the null-terminator. That's a reason you always want to use the form of functions (not applicable in this case) that read data, like, for example, sprintf() which should be calling snprintf() instead, and any other functions that can write into a buffer to be the form that let's you explicitly limit the length, so you don't get seriously hacked with a virus or exploit.
char alphabet[]={'a','b','c', ... ,'x','y','z'}; is not a string. It is simply an "array 26 of char".
In C, "A string is a contiguous sequence of characters terminated by and including the first null character. ...". C11 §7.1.1 1
strlen(alphabet) expects a string. Since code did not provide a string, the result is undefined.
To fix, insure alphabet is a string.
char alphabet[]={'a','b','c', ... ,'x','y','z', 0};
// or
char alphabet[]={"abc...xyz"}; // compiler appends a \0
Now alphabet is "array 27 of char" and also a string.
2nd issue: for(LG2=0;LG2<=strlen(lettersGuessed)-1;LG2++) has 2 problems.
1) Each time through the loop, code recalculates the length of the string. Better to calculate the string length once since the string length does not change within the loop.
size_t len = strlen(lettersGuessed);
for (LG2 = 0; LG2 <= len - 1; LG2++)
2) strlen() returns the type size_t. This is some unsigned integer type. Should lettersGuessed have a length of 0 (it might have been ""), the string length - 1 is not -1, but some very large number as unsigned arithmetic "wraps around" and the loop may never stop. A simple solution follows. This solution would only fail is the length of the string exceeded INT_MAX.
int len = (int) strlen(lettersGuessed);
for (LG2 = 0; LG2 <= len - 1; LG2++)
A solution without this limitation would use size_t throughout.
size_t LG2;
size_t len = strlen(lettersGuessed);
for (LG2 = 0; LG2 < len; LG2++)
Can someone explain the output of this simple program?
#include <stdio.h>
int main(int argc, char *argv[])
{
char charArray[1024] = "";
char charArrayAgain[1024] = "";
int number;
number = 2;
sprintf(charArray, "%d", number);
printf("charArray : %s\n", charArray);
snprintf(charArrayAgain, 1, "%d", number);
printf("charArrayAgain : %s\n", charArrayAgain);
return 0;
}
The output is:
./a.out
charArray : 2
charArrayAgain : // Why isn't there a 2 here?
Because snprintf needs space for the \0 terminator of the string. So if you tell it the buffer is 1 byte long, then there's no space for the '2'.
Try with snprintf(charArrayAgain, 2, "%d", number);
snprintf(charArrayAgain, 1, "%d", number);
// ^
You're specifying your maximum buffer size to be one byte. However, to store a single digit in a string, you must have two bytes (one for the digit, and one for the null terminator.)
You've told snprintf to only print a single character into the array, which is not enough to hold the string-converted number (that's one character) and the string terminator \0, which is a second character, so snprintf is not able to store the string into the buffer you've given it.
The second argument to snprintf is the maximum number of bytes to be written to the array (charArrayAgain). It includes the terminating '\0', so with size of 1 it's not going to write an empty string.
Check the return value from the snprintf() it will probably be 2.
In C, I would like to limit the string to the first 8 characters. For example, I have:
char out = printf("%c", str);
How can I make it so it only returns the first 8 characters?
You can limit the length by setting the precision in the format specifier:
printf("%.8s", str);
This will print up to eight characters from the null-terminated string pointed-to by str. If the length of str is less than eight characters, then it will print the entire string.
Note that the format specifier for a null-terminated string is %s, not %c (%c is to print a single char), and that printf returns an int (the total number of characters printed), not a char.
No
That is incorrect. tabular printing "%8s" pads up to say 8 spaces, as in the example given. It does not truncate. ISOC99. If this is a windows only thing, okay, MS ignores the world on lots of things. If the length of the string is longer than the tabulation then the full string prints. See:
int main()
{
char tmp[]="123456789";
printf("1 %1s\n", tmp);
printf("2 %2s\n", tmp);
printf("4 %4s\n", tmp);
printf("8 %8s\n", tmp);
printf("16 %16s\n", tmp);
printf("32 %32s\n", tmp);
return 0;
}
output from gcc 3.4.2 on Solaris 5.9:
> ./a.out
1 123456789
2 123456789
4 123456789
8 123456789
16 123456789
32 123456789
sprintf() will duplicate and truncate a string then it can be sent to printf. Or if you don't care about the source string:
char * trunc(char *src, int len)
{
src[len]=0x0;
return src;
}
References: INTERNATIONAL STANDARD ©ISO/IEC ISO/IEC 9899:TC2, WG14/N1124 Committee Draft — May 6, 2005