Is there a way to only print part of a string?
For example, if I have
char *str = "hello there";
Is there a way to just print "hello", keeping in mind that the substring I want to print is variable length, not always 5 chars?
I know that I could use a for loop and putchar or that I could copy the array and then add a null-terminator but I'm wondering if there's a more elegant way?
Try this:
int length = 5;
printf("%*.*s", length, length, "hello there");
This will work too:
fwrite(str, 1, len, stdout);
It will not have the overhead of parsing the format specifier. Obviously, to adjust the beginning of the substring, you can simply add the index to the pointer.
You can use strncpy to duplicate the part of your string you want to print, but you'd have to take care to add a null terminator, as strncpy won't do that if it doesn't encounter one in the source string. A better solution, as Jerry Coffin pointed out, is using the appropriate *printf function to write out or copy the substring you want.
While strncpy can be dangerous in the hands of someone not used to it, it can be quicker in terms of execution time compared to a printf/sprintf/fprintf style solution, since there is none of the overhead of dealing with the formatting strings. My suggestion is to avoid strncpy if you can, but it's good to know about just in case.
size_t len = 5;
char sub[6];
sub[5] = 0;
strncpy(sub, str + 5, len); // char[] to copy to, char[] to copy from(plus offset
// to first character desired), length you want to copy
printf and friends work well when that's all you want to do with the partial string, but for a more general solution:
char *s2 = s + offset;
char c = s2[length]; // Temporarily save character...
s2[length] = '\0'; // ...that will be replaced by a NULL
f(s2); // Now do whatever you want with the temporarily truncated string
s2[length] = c; // Finally, restore the character that we had saved
Related
I'm building a rocket for Elon Musk and the memory usage is very important to me.
I have text and a pointer to it pText. It's chilling in the heap.
Sometimes I need to analyse the string, its words. I don't store substrings in heap, instead I store two pointers start/end for represeting a substring of the text. But sometimes I need to print those substrings for debugging purposes. How do I do that?
I know that for a string to be printed I need two things
a pointer to the begging
null terminator at the end
Any ideas?
// Text
char *pText = "We've sold the Earch!";
// Substring `sold`
char *pStart = &(pText + 6) // s
char *pEnd = &(pStart + 3) // d
// Print that substring
printf("sold: %s", ???);
If you only want to print the sub-string, then use a precision argument for printf:
printf("sold: %.*s", (int) (pEnd - pStart) + 1, pStart);
If you need to use the sub-string in other ways then the simplest is probably to create a temporary string, copy into it, and then print that instead.
Perhaps something like this:
// Get the length of the sub-string
size_t length = pEnd - pStart + 1;
// Create an array for the sub-string, +1 for the null-terminator
char temp[length + 1];
// Copy the sub-string
memcpy(temp, pStart, length);
// Terminate it
temp[length] = '\0';
If you need to do this many times I recommend you create a generic function for this.
You might also need to dynamically allocate the string using malloc depending on use-case.
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'm relatively new to C. I wanted to lern the language a bit by solving coderbyte challenges.
But I'm stucked at the first. It is supposed to be a simple String reverse algorithm.
When I input things like "asdf" or "1234567" the output is correct ("fdsa", "7654321"). But when I type "12345678" or "thisiscool" I get "87654321▒#"/"loocsisiht#" as a result. I don't know where the # are comming from.
This is my code:
#include <stdio.h>
#include <string.h>
void FirstReverse(char str[]) {
int len = strlen(str);
char nstr[len];
int i;
for(i = 0; i < len; i++) {
nstr[i] = *(str+len-1-i);
}
printf("%s\n", nstr);
}
int main(void) {
char str[100];
FirstReverse(gets(str));
return 0;
}
Can someone please tell me where I can find the error?
Thanks in advance :)
In C, strings are zero-terminated. A string "cat", for example, has 4 characters, and is represented as ('c','a','t',(char)0). You forgot about the final 0.
Note that strlen returns the string length without the final 0, so a string foo contains strlen(foo)+1 characters. Remember this when you allocate strings.
As the other answers have mentioned, you're missing a terminator.
It should also be noted that it's bad practice to allocate strings the way you did. An array should always have a fixed size if you create it that way.
You should instead do:
char * nstr = malloc(sizeof(char) * (len+1));
Thereby allocating the size of each character (1 byte) times the lenght.
Note the +1 because you need room for the string terminator.
When you call printf(, string); , it's gonna start from the first letter and print everything up to the terminator. Since you have no terminator here, it prints random characters, such as #.
What you're gonna wanna do to fix that, is adding:
nstr[i] = '\0';
after your loop.
Also remember to free the allocated memory.
You forgot to allocate a char for the terminating '\0' in nstr[].
So, better use: char nstr[len + 1]; and set nstr[len] = 0;
Furthermore: gets() is evil: from the glibc manual page:
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
Just double checking because I keep mixing up C and C++ or C# but say that I have a string that I was parsing using strcspn(). It returns the length of the string up until the first delimiter it finds. Using strncpy (is that C++ only or was that available in C also?) I copy the first part of the string somewhere else and have a variable store my position. Let's say strcspn returned 10 (so the delimiter is the 10th character)
Now, my code does some other stuff and eventually I want to keep traversing the string. Do I have to copy the second half of the string and then call strncspn() from the beginning. Can I just make a pointer and point it at the 11th character of my string and pass that to strncspn() (I guess something like char* pos = str[11])? Something else simpler I'm just missing?
You can get a pointer to a location in the middle of the string and you don't need to copy the second half of the string to do it.
char * offset = str + 10;
and
char * offset = &str[10];
mean the same thing and both do what you want.
You mean str[9] for the 10th char, or str[10] for the 11th, but yes you can do that.
Just be careful that you are not accessing beyond the length of the string and beyond the size of memory allocated.
It sounds like you are performing tokenization, I would suggest that you can directly use strtok instead, it would be cleaner, and it already handles both of what you want to do (strcspn+strncpy and continue parsing after the delimiter).
you can call strcspn again with (str + 11) as first argument. But make sure that length of str is greater than 11.
n = strcspn(str, pattern);
while ((n+1) < strlen(str))
{
n2 = strcspn((str+n), pattern);
n += n2;
}
Note : using char *pos = str[11] is wrong. You should use like char *pos = str + 11;
Hi im trying to find the - char and then place the leftmost characters into a string. Here i would like FUPOPER to be stored in program_id_DB, however when i run this code my output results to:
Character '-' found at position 8.
The prgmid contains FUPOPERL <-where is it getting this l?!?!
char data_DB[]="FUPOPER-$DSMSCM.OPER*.FUP";
char program_id_DB[10];
char program_name_DB_c[ZSYS_VAL_LEN_FILENAME];
char *pos = strchr(data_DB, '-');
if (pos)
strncpy(program_id_DB,data_DB, pos-data_DB);
printf("Character '-' found at position %d.\n", pos-data_DB+1);
printf("The prgmid contains %s\n",program_id_DB);
You didn't initialize program_id_DB, so it's free to contain anything it wants. Set it to zero before you start:
memset(program_id_DB, 0, 10);
(You need to #include <string.h> for memset.)
In fact, what you're doing is terribly dangerous because there's no guarantee that the string you pass to printf is null-terminated! Always zero the array before use and copy at most 9 non-null characters into it.
You need to put a \0 to mark the string's end.
A way to do it is: memset(program_id_DB, 0, sizeof(program_id_DB)); before you strncpy to it.
You have to append a null-terminating character at the end of the program_id_DB string as strncpy does not do this automatically for you if you've already copied N characters (i.e., in your case you're copying a total of eight characters, so there will not be a null-terminating character copied into the buffer if you copy more than seven characters). Either that, or zero-initialize your program-id_DB string using memset before using it with strncpy.
strncpy is a bitch!
It doesn't terminate the string. You need to terminate the string yourself.
if (pos) {
strncpy(program_id_DB,data_DB, pos-data_DB);
program_id_DB[pos - data_DB] = 0;
}
And if the string is too small, strncpy will set the remainder with zeros.
strncpy(dst, src, 1000); /* always writes 1000 bytes, whether it needs to */