I have two strings, e.g.:
str1 = "aaabbbcccdddeee"
str2 = "aaabbbccc"
How to do something like str1 - str2 to get the dddeee substring?
If str2 is guaranteed to be a prefix of str1, then this will suffice:
const char *str3 = &str1[strlen(str2)];
which is equivalent to this: (as #James points out in the comments)
const char *str3 = str1 + strlen(str2);
Of course, str3 is just a pointer into one of the original strings. If the contents of the original string changes, then so will your result. So you may want to create a copy, using malloc() and strcpy() (and then free() at some point).
This will skip the common prefix of two strings:
char* suffix(const char* prefix, const char* str) {
while (*prefix && *str && *prefix == *str) {
prefix++;
str++;
}
return str;
}
For example, if you pass "AAB" and "AACC", this would return "CC".
str3 will contain a copy of the prefix:
str1 = "aaabbbcccdddeee"
str2 = "aaabbbccc"
size_t length = strlen1 - strlen2;
char* str3 = calloc(sizeof(char), length + 1);
memcpy(str3, str1+strlen(str2), length);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a[] = "aaaabbbbbdddeee";
char b[] = "aaaabbbbb";
const char* start = strstr(a, b);
if (start)
{
printf("%s\n", a + strlen(b));
}
return 0;
}
Since you have clarified that str2 is a prefix of str1, you can get the pointer to the extra part in str2 simply with the operation:
str1 + strlen(2);
For example, to print the "dddeee" part of your string:
printf("%s\n", str1 + strlen(str2));
How this works is simple. str1 + strlen(str2) is a pointer that is strlen(str2) N characters away from the beginning of the string pointed to be str1. strlen(str2) returns the number of characters in the second string and you skip those many characters in the first string and reach the extra part.
Related
I need to concatenate the strings "abc" and "def" using strlen but without using strcat. Can someone show me what is wrong with my main() function?
#include <stdio.h>
#include <string.h>
void strconcatenate(char *string1, char *string2) {
int i;
int j = strlen(string1);
for (i = 0; string2[i]; i++) {
string1[i+j] = string2[i];
}
string1[i + j]= '\0';
}
int main() {
char string1[3] = "abc";
string1[strlen(string1) - 1] = '\0';
char string2[3] = "def";
string2[strlen(string2) - 1] = '\0';
strconcatenate(string1, string2);
printf("Resultant string = %s\n", string1);
return 0;
}
In main you declared character arrays with three elements
char string1[3] = "abc";
//...
char string2[3] = "def";
These arrays do not contain strings because they do not store the terminating zero character '\0' of the string literals used as initializers. The first array contains three characters { 'a', 'b', 'c' } and the second array contains these three characters { 'd', 'e', 'f' }.
Then you applied the standard string function strlen to these arrays which expects that passed to it arrays contains strings. That is the function calculates the number of characters in a string by counting characters until the terminating zero character is encountered. As the arrays do not contain the terminating zero character '\0' that is as the arrays do not contain strings the calls of strlen invoke undefined behavior.
If you want to append one string to another string then the destination character array shall have enough size to be able to accommodate the second string.
Thus the function main can look the following way
int main( void ) {
char string1[7] = "abc";
char string2[] = "def";
printf( "Resultant string = %s\n", strconcatenate( string1, string2 ) );
return 0;
}
Now the both arrays string1 and string2 contain strings. Moreover the array string1 reserved enough space to accommodate the string stored in the array string2.
The declaration of the function strconcatenate should be similar to the declaration of the standard C function strcat.
char * strconcatenate( char *string1, const char *string2 );
That is the second parameter should have the qualifier const because the passed array is not changed within the function and the function should return the destination array that will contain the concatenated strings.
The function definition will look the following way
char * strconcatenate( char *string1, const char *string2 )
{
for ( char *p = string1 + strlen( string1 ); *p++ = *string2++; );
return string1;
}
There are multiple problems in your code:
[major] char string1[3] = "abc"; defines the destination array with a size of 3 bytes which does not have a enough space for the string "abc" including its null terminator and definitely not long enough to receive the extra characters from string2 at the end. Change this to char string1[7] = "abc";
[major] char string2[3] = "def"; defines the source array with a size of 3 bytes which does not have a enough space for the string "def" including its null terminator, hence will not be null terminated.
[major] string1[strlen(string1) - 1] = '\0'; overwrites the last character of abc, this not necessary.
[major] same remark for string2[strlen(string2) - 1] = '\0';
[minor] string2 should be defined as const char * in void strconcatenate(char *string1, char *string2)
[minor] i and j should be defined with type size_t
[minor] for compatibility with the standard function strcat, strconcatenate should have a return type of char * and return the pointer to the destination array. Yet, As commented by Jonathan Leffler, a more useful design for the return value is to return a pointer to the null at the end of the concatenated string. You already know where the start of the string is; that isn't very interesting information. But knowing where the end of the string is after concatenation — that is useful information which only the concatenate function is privy to. –
Here is a modified version:
#include <stdio.h>
#include <string.h>
char *strconcatenate(char *string1, const char *string2) {
char *p = string1 + strlen(string1);
while ((*p = *string1) != '\0') {
string1++;
p++;
}
return string1; /* strcat semantics */
//return p; /* alternative semantics */
}
int main() {
char string1[7] = "abc";
char string2[] = "def";
strconcatenate(string1, string2);
printf("Resultant string = %s\n", string1);
return 0;
}
Since string1 and string2 has 3 characters so you need to declare it with 4 bytes('\0') and also when you need not to subtract 1 from strlen because it points to '\0' character.
Below is the change to the code.
int main()
{
char string1[4] = "abc";
string1[strlen(string1)] = '\0';
char string2[4] = "def";
string2[strlen(string2)] = '\0';
strconcatenate(string1,string2);
printf("Resultant string = %s\n",string1);
return 0;
}
why does the following string concatenation does not work?
main()
{
char *str1 = "United";
char *str2= "Front";
char *str3;
str3 = strcat(str1, str2 ) ;
printf("\n%s",str3 );
}
I got this problem in exercise questions in one of a book on pointers. The question mentions
[Q] Is the code correct if not why and also correct the code.
See my answer to the question concatenation of character arrays in c
You may not change string literals.
This statement
str3 = strcat(str1, str2 ) ;
tries to change the string literal str1 and moreover tries to write beyond the string literal.
To make a concatenated string you have to allocate a memory large enough to contain the both strings.
What you need is the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *str1 = "United";
const char *str2 = "Front";
char *str3 = malloc( strlen( str1 ) + strlen( str2 ) + 1 );
strcpy( str3, str1 );
puts( strcat( str3, str2 ) );
free( str3 );
return 0;
}
The program output is
UnitedFront
When you write char* s = "something" a piece of read-only memory is allocated. More on this here.
The declaration of strcat looks like this:
char *strcat( char *dest, const char *src );
Basically what it will do is append src to dest, but since your destination, str1 does not have enough memory to hold both strings.
So what I would do is, either use snprintf with a pre-allocated buffer or:
char *str1 = "United";
char *str2 = "Front";
char *buf = calloc(strlen(str1) + strlen(str2) + 1, sizeof(char));
strncpy(buf, str1, strlen(str1));
strncat(buf, str2, strlen(str2));
printf("%s", buf);
Or with snprintf:
char *str1 = "United";
char *str2 = "Front";
int buf_len = strlen(str1) + strlen(str2) + 1;
char *buf = calloc(buf_len, sizeof(char));
snprintf(buf, buf_len, "%s%s", str1, str2);
The first parameter of strcat (str1 in your case) needs to have enough allocated memory to hold the concatenated string.
You can either create it with malloc or declare it as an array with a big enough size.
I have two ways to do the same purpose, the first-way prints unknown symbols and the second-way prints exactly what I want.
The first-way:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1), *p = str;
while (*constStr) {
*p = *constStr;
constStr++;
p++;
}
printf("%s\n", str);
free(str);
The result:
The second-way:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1);
for (int i = 0; i <= strlen(constStr); i++) {
str[i] = constStr[i];
}
printf("%s\n", str);
free(str);
The result:
Why the first-way the result seems strange?
No you didn't null terminate the string. This is undefined behavior to pass pointer to non-null terminated char array in printf using %s format specifier.
Outside the loop make *p=0. That will null terminate the char array.
Second way is printing because you copied the \0 which is in strlen(constStr) index of the array. Notice the <= in the loop condition.
From where those weird letters come?
Think in terms of printf. When it sees the %s format specifier it prints starting from the address provided to it as argument. Now when does it stop? when it finds the \0. here it didnt find it and it read out of the memory that you allocated. Those bit patterns on those memory turned out to be those non printable characters. That's what you saw. The correct way to do this would be:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr) + 1), *p = str;
while (*p++ = *constStr++); // here `\0` will be copied.
printf("%s\n", str);
free(str);
When working with strings make sure you keep the corner cases clean. By that I mean,check whether the \0 is copied or not etc. This is so common a problem when we implement string routines.
To fix the first one, add a null at the end of the string:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1), *p = str;
while (*constStr) {
*p = *constStr;
constStr++;
p++;
}
*p = '\0'; /* <-- HERE */
printf("%s\n", str);
free(str);
Note: you are modifying a pointer to a temporary - not recommended. Use the same approach as you did for str, by using a another pointer which gets shifted.
I have a chunk of memory I'm declaring on the heap.
char *str;
str = (char *)malloc(sizeof(char) * 10);
I have a const string.
const char *name = "chase";
Because *name is shorter than 10 I need to fill str with chase plus 5 spaces.
I've tried to loop and set str[i] = name[i] but there's something I'm not matching up because I cannot assign spaces to the additional chars. This was where I was going, just trying to fill str with all spaces to get started
int i;
for (i = 0; i < 10; i++)
{
strcpy(str[i], ' ');
printf("char: %c\n", str[i]);
}
As the others pointed out, you need
//malloc casting is (arguably) bad
str = malloc(sizeof(char) * 11);
and then, just do
snprintf(str, 11, "%10s", name);
Using snprintf() instead of sprintf() will prevent overflow, and %10swill pad your resulting string as you want.
http://www.cplusplus.com/reference/cstdio/snprintf/
If you want str to have 10 characters and still be a C-string, you need to '\0' terminate it. You can do this by mallocing str to a length of 11:
str = malloc(11);
Note there's no need to cast the return pointer of malloc. Also, sizeof(char) is always 1 so there's no need to multiply that by the number of chars that you want.
After you've malloc as much memory as you need you can use memset to set all the chars to ' ' (the space character) except the last element. The last element needs to be '\0':
memset(str, ' ', 10);
str[10] = '\0';
Now, use memcpy to copy your const C-string to str:
memcpy(str, name, strlen(name));
easy to use snprintf like this
#include <stdio.h>
#include <stdlib.h>
int main(){
char *str;
str = (char *)malloc(sizeof(char)*10+1);//+1 for '\0'
const char *name = "chase";
snprintf(str, 11, "%-*s", 10, name);//11 is out buffer size
printf(" 1234567890\n");
printf("<%s>\n", str);
return 0;
}
This is purely for self-interest and is not a homework assignment.
#include <stdio.h>
int main(void)
{
char* str3;
char* str1 = "Hello";
char* str2 = "World!";
while(*str1) str1++;
while(*str1++ = *str2++);
return 0;
}
I am attempting to develop a better understanding of C pointers and in doing so I would like to concatenate two strings and place the result into a third string. The (incomplete) code above results in a segfault and I'm not sure why. Isn't it possible to loop over the value referenced by a pointer and copy the data to another address?
Edit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char* str1 = "Hello";
char* str2 = "World!";
char *str3 = malloc(strlen(str1) + strlen(str2) + 1);
while(*str1) *str3++ = *str1++;
while(*str2) *str3++ = *str2++;
puts(str3);
return 0;
}
The new attempt is above, and while not functional, are there "obvious" items I need to fix?
while(*str1) str1++;
This advances str1 until it points to the terminating zero byte at the end of the string constant.
while(*str1 = *str2++);
This modifies the terminating zero byte at the end of the string, but the string is a constant and so can't be modified.
If you want to assemble a string in memory, you need to allocate some space to do that in or use functions that do so. You could do:
char *new_string = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(new_string, str1);
strcat(new_string, str2);
The first line allocates enough space to hold str1's contents, str2's contents, and the terminating zero byte.
int main(void)
{
char* str1 = "Hello";
char* str2 = "World!";
// allocate one more byte for string terminate cher ('\n')
int size = strlen(str1) + strlen(str2);
char* str3 = (char*)malloc(size + 1);
char* str_mod = str3;
while( (*str_mod++ = *str1++) != '\0');
str_mod--;
while( (*str_mod++ = *str2++) != '\0');
printf ( "%s", str3);
free (str3);
return 0;
}
The constant strings are not modifyable. You are not modifying str3.
You need to
get the length of str1 and str2.
malloc length of str1 + length str2 + 1 and assign to str3
You can use while loops if you like for the copy, or you can use strcpy and strcat to copy the strings to str3.
Since you are trying to learn, I am trying not to write the code for you.
int main (void){
char* str1 = "Hello";
char* str2 = "World";
int size1 = strlen(str1);
int size2 = strlen(str2);
int i = 0;
char* out = malloc(sizeof(char)*(size1+size2)+1);
for (i = 0; i < size1; i++){
out[i] = str1[i];
}
for (i = 0; i < size2; i++){
out[i+size1] = str2[i];
}
out[strlen(out)-1] = \0;
//out is a string.
//dont forget to free when you are done. free(out);
}
Its been a few months since i did C, but this would work. my syntax might be slightly off.
2nd attempt in question misses putting string terminating null to end of str3. So puts reads beyond end of data, prints garbage and may even crash if there is no 0 byte before reading invalid address. Add *str3 ='\0'; after loops.
Additionally, you modify str3 and lose start of string. Add one more variable, keep the pointer returned by malloc, and pass that to puts. Current code will start printing at the end of the new string.
Then when you have pointers to string literals, make them pointers to const char, because usually string literals are in read only memory area:
const char* str1 = "Hello";
const char* str2 = "World!";