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.
Related
I am new to C language. I need to concatenate char array and a char. In java we can use '+' operation but in C that is not allowed. Strcat and strcpy is also not working for me. How can I achieve this? My code is as follows
void myFunc(char prefix[], struct Tree *root) {
char tempPrefix[30];
strcpy(tempPrefix, prefix);
char label = root->label;
//I want to concat tempPrefix and label
My problem differs from concatenate char array in C as it concat char array with another but mine is a char array with a char
Rather simple really. The main concern is that tempPrefix should have enough space for the prefix + original character. Since C strings must be null terminated, your function shouldn't copy more than 28 characters of the prefix. It's 30(the size of the buffer) - 1 (the root label character) -1 (the terminating null character). Fortunately the standard library has the strncpy:
size_t const buffer_size = sizeof tempPrefix; // Only because tempPrefix is declared an array of characters in scope.
strncpy(tempPrefix, prefix, buffer_size - 3);
tempPrefix[buffer_size - 2] = root->label;
tempPrefix[buffer_size - 1] = '\0';
It's also worthwhile not to hard code the buffer size in the function calls, thus allowing you to increase its size with minimum changes.
If your buffer isn't an exact fit, some more legwork is needed. The approach is pretty much the same as before, but a call to strchr is required to complete the picture.
size_t const buffer_size = sizeof tempPrefix; // Only because tempPrefix is declared an array of characters in scope.
strncpy(tempPrefix, prefix, buffer_size - 3);
tempPrefix[buffer_size - 2] = tempPrefix[buffer_size - 1] = '\0';
*strchr(tempPrefix, '\0') = root->label;
We again copy no more than 28 characters. But explicitly pad the end with NUL bytes. Now, since strncpy fills the buffer with NUL bytes up to count in case the string being copied is shorter, in effect everything after the copied prefix is now \0. This is why I deference the result of strchr right away, it is guaranteed to point at a valid character. The first free space to be exact.
strXXX() family of functions mostly operate on strings (except the searching related ones), so you will not be able to use the library functions directly.
You can find out the position of the existing null-terminator, replace that with the char value you want to concatenate and add a null-terminator after that. However, you need to make sure you have got enough room left for the source to hold the concatenated string.
Something like this (not tested)
#define SIZ 30
//function
char tempPrefix[SIZ] = {0}; //initialize
strcpy(tempPrefix, prefix); //copy the string
char label = root->label; //take the char value
if (strlen(tempPrefix) < (SIZ -1)) //Check: Do we have room left?
{
int res = strchr(tempPrefix, '\0'); // find the current null
tempPrefix[res] = label; //replace with the value
tempPrefix[res + 1] = '\0'; //add a null to next index
}
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;
I have a char array filled with some characters. Let's say I have "HelloWorld" in my char array. (not string. taking up index of 0 to 9)
What I'm trying to do is insert a character in the middle of the array, and push the rest to the side to make room for the new character that is being inserted.
So, I can make the char array to have "Hello.World" in it.
char ch[15]; // assume it has "HelloWorld" in it
for(int i=0; i<=strlen(ch)-1; i++) {
if(ch[i]=='o' && ch[i+1]=='W') {
for(int j=strlen(ch)-1; j>=i+2; j--) {
ch[j] = ch[j-1]; // pushing process?
}
ch[i+1] = '.';
break;
}
}
Would this work? Would there be an easier way? I might just be thinking way too complicated on this.
You need to start the inner loop from strlen(ch) + 1, not strlen(ch) - 1, because you need to move the NULL-terminator to the right one place as well. Remember that strlen returns the length of the string such that string[strlen(string)] == '\0'; you can think of strlen as a function for obtaining the index of the NULL-terminator of a C-string.
If you want to move all the characters up by one, then you could do it using memmove.
#include <string.h>
char ch[15];
int make_room_at = 5;
int room_to_make = 1;
memmove(
ch + make_room_at + room_to_make,
ch + make_room_at,
15 - (make_room_at + room_to_make)
);
Simply do:
#define SHIFT 1
char bla[32] = "HelloWorld"; // We reserve enough room for this example
char *ptr = bla + 5; // pointer to "World"
memmove(ptr + SHIFT, ptr, strlen(ptr) + 1); // +1 for the trailing null
The initial starting value for the inner loop is one short. It should be something like the following. Note too that since the characters are moved to the right, a new null terminator needs to be added:
ch[strlen(ch) + 1] = '\0';
for(j=strlen(ch); j>=i+2; j--) { // note no "-1" after the strlen
Edit As far as the "Is this a good way?" part, I think it is reasonable; it just depends on the intended purpose. A couple thoughts come to mind:
Reducing the calls to strlen might be good. It could depend on how good the optimizer is (perhaps some might be optimized out). But each call to strlen require a scan of the string looking for the null terminator. In high traffic code, that can add up. So storing the initial length in a variable and then using the variable elsewhere could help.
This type of operation has the chance for buffer overflow. Always make sure the buffer is long enough (it is in the OP).
If you're going to manipulate a char array you shouldn't make it static. By doing this:
char ch[15];
you're hardcoding the array to always have 15 characters in it. Making it a pointer would be step 1:
char* ch;
This way you can modify it as need be.
I have a function in C where i am trying to get strings from two different locations (unknown size, could be quiet large) and combine them into one string and return them. If i just print the two strings then I get the correct result, but when I try to combine the strings using strcat I end up with 5 garbage characters and then the result of the combined strings.
Anyone have some advice as to what I am doing wrong? Here is some sample code to demonstrate what I am doing:
static int get_information(char** results)
{
size_t s1_length;
size_t s2_length;
/* DEBUGGING - Prints the correct string */
printf(get_string_1());
printf(get_string_2());
printf("\n");
/* Allocate memory for new string */
s1_length = strlen(get_string_1());
s2_length = strlen(get_string_2());
*results = malloc(sizeof(char) * (dir_length + file_length));
if(results == NULL)
return -1;
/* Combine the strings */
strcat(*results, get_string_1());
strcat(*results, get_string_2());
/* DEBUGGING - prints 5 garbage characters then the correct string */
printf(*results);
printf("\n");
return 0;
}
strcat needs to find the null terminator in the destination. Your *result points to uninitialised memory, which happens to have a null terminator 5 characters in.
Adding *result[0]='\0'; just before combining the strings should fix it.
Also, you are not allocating enough space for the null terminator in *result.
Why do you strcat the first string? Simply copy it. Otherwise it will append to whatever garbage is in the uninitialized memory ...
/* Combine the strings */
strcpy(*results, get_string_1());
strcat(*results, get_string_2());
strcat() assumes the destination to be a valid string, so make it so by adding
*results[0] = '\0';
before you do strcat()
Alternatively try doing these:
strcpy(*results, get_string_1());
strcat(*results, get_string_2());
Lastly, what exactly is happening in this line:
*results = malloc(sizeof(char) * (dir_length + file_length));
Make sure you allocate enough space to results. Ideally it should be:
*results = malloc(sizeof(char) * (s1_length+s2_length+1));
for allocating enough space as s1 and s2 and followed by a terminating '\0' character.
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