This question already has answers here:
Concatenating strings in C
(5 answers)
Closed 9 years ago.
I have a method that concatenates two c string. The method returns a new one. It works fine. Is there a way to make this method void, and just modify the first one?
EDIT: I cannot use strcopy or any other function from the string.h library. It is also suppose to be up to the caller to make sure s1 has enough space to accommodate s2.
char *str_glue(char *s1, char *s2)
{
char *r; //return string
int len1, len2;
int i, j;
len1 = str_length(s1);
len2 = str_length(s2);
if ((r=(char*)malloc(len1 + len2 + 1))==NULL)
{
return NULL;
}
for (i=0, j=0; i<len1; i++, j++) {
r[j] = s1[i];
}
for (i=0; i<len2; i++, j++)
{
r[j] = s2[i];
}
r[j] = '\0';
return r;
}
int main() {
char* x = "lightning";
char* y = "bug";
char *z = str_glue(x, y);
printf("%s\n", z);
}
Not really. *s1 is a char[] that already has a fixed length. If you write past that length you'll stomp on memory that is not inside of *s1. You have to create a new one that is the length of *s1 + *s2 to avoid this problem like you have done already.
Edit: I guess you could write a function that does what you want if *s1 is big enough to hold itself and *s2. But otherwise, no.
Use the standard function strcat():
The strcat() and strncat() functions append a copy of the null-terminated string s2 to the end of the null-terminated string s1,
then add a terminating `\0'. The string s1 must have sufficient space to hold the result.
You could consider using realloc of s1 provided you allocate the same on the heap. By modifying your code as this, I am able to achieve the same functionality as expected by you.
void str_glue(char **s1, char *s2)
{
int len1, len2;
int i;
char *curstr = *s1;
len1 = strlen(curstr);
len2 = strlen(s2);
curstr=(char*)realloc(curstr, (len1 + len2 + 1));
for (i=0; i<len2; i++)
{
curstr[(len1+i)] = s2[i];
}
curstr[(len1+len2)] = '\0';
}
and main function as
int main()
{
char* x;
char* y = "bug";
x = (char *)malloc(32);
strcpy(x, "lightning");
str_glue(&x, y);
printf("%s\n", x);
}
You would require to include stdlib.h for realloc definition.
P.S: I am assuming that you don't plan to use the standard C library functions like strcat or others.
Related
I am trying to reverse a string. scanf is working well but when I use fixed string then it gives garbage value. So where is the fault ?
#include<stdio.h>
#include<string.h>
int main()
{
char s[50]="Hi I Love Programming";
char rev[strlen(s)];
int i,k;
k=strlen(s);
for(i=0; i<strlen(s); i++)
{
rev[k]=s[i];
k--;
}
printf("The reverse string is: %s\n", rev);
}
Your program has two issues:
1.
char rev[strlen(s)];
You forgot to add an element for the string-terminating null character '\0'.
Use:
char rev[strlen(s) + 1];
Furthermore you also forgot to append this character at the end of the reversed string.
Use:
size_t len = strlen(s);
rev[len] = '\0';
Note, my len is the k in your provided code. I use the identifier len because it is more obvious what the intention of that object is. You can use strlen(s) because the string has the same length, doesn´t matter if it is in proper or reversed direction.
2.
k=strlen(s);
for(i=0; i<strlen(s); i++)
{
rev[k]=s[i];
k--;
}
With rev[k] you accessing memory beyond the array rev, since index counting starts at 0, not 1. Thus, the behavior is undefined.
k needs to be strlen(s) - 1.
Three things to note:
The return value of strlen() is of type size_t, so an object of type size_t is appropriate to store the string length, not int.
It is more efficient to rather calculate the string length once, not at each condition test. Use a second object to store the string length and use this object in the condition of the for loop, like i < len2.
char s[50]="Hi I Love Programming"; can be simplified to char s[]="Hi I Love Programming"; - The compiler automatically detects the amount of elements needed to store the string + the terminating null character. This safes unnecessary memory space, but also ensures that the allocated space is sufficient to hold the string with the null character.
The code can also be simplified (Online example):
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "Hi I Love Programming";
size_t len = strlen(s);
char rev[len + 1];
size_t i,j;
for(i = 0, j = (len - 1); i < len; i++, j--)
{
rev[j] = s[i];
}
rev[len] = '\0';
printf("The reverse string is: %s\n", rev);
}
Output:
The reverse string is: pgnimmargorP evoL I iH
your program is hard to understand. Here you have something much simpler (if you want to reverse the string of course)
#include <stdio.h>
#include <string.h>
char *revstr(char *str)
{
char *start = str;
char *end;
if(str && *str)
{
end = str + strlen(str) - 1;
while(start < end)
{
char tmp = *end;
*end-- = *start;
*start++ = tmp;
}
}
return str;
}
int main()
{
char s[50]="Hi I Love Programming";
printf("%s", revstr(s));
}
https://godbolt.org/z/5KX3kP
I am working to learn C using Kochan's Programming in C 4th edition. problem 9.7 the goal is to insert a string of characters into another array. I am supposed to write a function to accomplish this. I have two problems.
When I have the algorithm print the result as it goes through the if statements, it produces the desired output, however when I change it to an %s, I only get a partial output. My hunch is that a null character is being placed where i do not want it, but I simply cannot see it.
To see what was happening, I added a printf that would track the letter and the array space it was occupying. I was surprised to see that the first letter was not 0, but was blank, and the next letter was assigned the 0. Any insight into this would be appreciated.
The funtion of interest is "insertString".
#include <stdio.h>
#include <stdbool.h>
char x[] = {"the wrong son was shot that day"};
char text[] = {"per"};
int countString (char x[])
{
int counter, z;
for (counter = 0; x[counter] != '\0'; ++counter)
z = counter+1;
return z;
}
void insertString (char text[],char x[],int n) //source, text to input, where
{
int count, clock, i = countString(text), q = countString(x);
int counter = 0;
char y[i + q];
for(count = 0; x[count] != '\0'; ++count){
if (count < n){
y[count] = x[count];
printf("%c %i", y[count], count); //The integer call is just to put a number next to the
//letter. This is where my second issue is shown.
}
else if (counter <= i){
y[count] = text[counter];
++counter;
printf("%c", y[count]);
}
else{
y[count]= x[count - counter];
printf("%c", y[count]);
}
}
printf("\n\n");
y[count-counter] = '\0';
printf("%s", y);
}
int main (void)
{
void insertString(char text[], char x[], int i);
int countString(char x[]);
int i;
insertString(text, x, 10);
return 0;
}
10 out of 10 times I post here it is because im doing something dumb, so I use SO as an absolute last resort if i am getting into the territory of just randomly trying stuff with no methodology. Thanks for your patience in advance.
Your condition is wrong in the for. It should be x[count - counter] != '\0'
In the second condition use just < to avoid overindexing. (else if (counter < i))
You put the terminating NULL char at wrong place. You should do this: y[count] = '\0'
printf inside a string routine like this is fine for debugging, but it's a poor way to write a general-purpose function because it makes it impossible to use its output for further programmatic manipulation. It can also make it difficult to reason about how the state of the function interacts in unpredictable ways with the state of the printed data.
I assume you haven't learned about dynamic memory allocation which is a prerequisite to returning strings from functions. You can inline the function logic into main or printf only at the end of the function in the meantime.
Adding to this point, a void function would need to reallocate space in the string to insert into and would be in-place. This seems likely less generally useful than allocating a new string to hold the result.
Using global variables like char x[] when there's no need is poor practice. It's better to put those strings scoped to main. Since your function can access these variables in addition to its parameters, confusion can ensue when scope and encapsulation is breached.
Use consistent formatting and avoid variable names like q that mean virtually nothing. Instead of adding comments to explain poor var names:
void insertString (char text[],char x[],int n) //source, text to input, where
You can simply name the variables exactly what they represent:
void insertString(char *dest, char *source, int add_index)
Also, now that you've mastered countString, you can abstract this by calling the builtin strlen.
Be sure to allocate enough space in buffers: char y[i + q]; should be y[i+q+1] to allow room for the null terminator '\0'.
As for the logic, I think it's easier to break into three loops without conditions instead of one loop with conditions. This makes it easier to break the problem down into the three constituent steps:
Add everything up until add_index from the dest string to the result.
Add everything in the source string to the result.
Add everything after add_index from the dest string to the result.
Using this approach, all that's left is figuring out how to map the indexes appropriately. Here it is in code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
int result_size = source_len + dest_len + 1;
char *result = malloc(result_size);
for (int i = 0; i < add_index; i++) {
result[i] = dest[i];
}
for (int i = 0; i < source_len; i++) {
result[i+add_index] = source[i];
}
for (int i = add_index; i < dest_len; i++) {
result[i+add_index] = dest[i];
}
result[result_size-1] = '\0';
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Although this is likely for instructional purposes, these operations can be abstracted further using builtin string functions like strncpy and sprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int result_size = strlen(dest) + strlen(source) + 1;
char *result = malloc(result_size);
char pre[add_index+1];
pre[add_index] = '\0';
strncpy(pre, dest, add_index);
sprintf(result, "%s%s%s", pre, source, dest + add_index);
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Doing this in-place is more straightforward. Since the result already has the prefix, you can copy the destination postfix to create a source-sized gap in the middle and then overwrite the gap using the source string. It's up to the caller to make sure that the destination buffer is large enough to hold the insertion.
#include <stdio.h>
#include <string.h>
void insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
for (int i = add_index; i < dest_len; i++) {
dest[i+add_index] = dest[i];
}
for (int i = 0; i < source_len; i++) {
dest[i+add_index] = source[i];
}
}
int main(void) {
// allocate extra space in the string to hold the insertion
char greeting[32] = "hello world";
insert_string(greeting, "cruel ", 6);
printf("%s\n", greeting);
return 0;
}
A note of caution: none of these functions handle errors at all, so they're unsafe. Correct functions should check that the add_index falls within the bounds of the dest string. This is an exercise for the reader.
The original exercise is here:
Your function is not doing it. You need to insert the string into another string not to create a new one with both mixed. You can do it this way of course and then copy it into the original one - but it is the most uneficient way to archive it (memory & timewise).
Use the correct types.
size_t mystrlen(const char *str)
{
const char *end = str;
while(*end++);
return end - str - 1;
}
char *strinsert(char *dest, size_t pos, const char *istr)
{
char *temp = dest, *work;
size_t ilen = mystrlen(istr);
size_t nmove;
while(*temp) temp++;
nmove = temp - dest - pos + 1;
work = temp;
temp += ilen;
while(nmove--) *temp-- = *work--;
work = dest + pos;
while(*istr) *work++ = *istr++;
return dest;
}
int main()
{
char dest[128] = "0123456789012345678901234567890123456789";
printf("%s", strinsert(dest, 7, "ABCD"));
}
https://godbolt.org/z/KMnLU2
This question already has answers here:
Extra characters added to end of string in c
(3 answers)
Closed 5 years ago.
I am writing a function in C which takes two strings of the same length,
for example:-
S1 = "Hello" and S2 = "12345"
and returns a result that mixes the characters from the input strings so that the first char in the result string is the first char from S1, the second char is the first char from S2, the third char in r is the second char from S1 and the fourth char in r is the second char from S2, and so on....
So if:-
S1 = "Hello"
S2 = "12345"
Result = "H1e2l3l4o5"
My function looks like this:
#include <stdio.h>
#include <string.h>
char* mix(char *s1, char *s2)
{
int length = strlen(s1);
char* result = malloc(sizeof(char) * length * 2);
int i, j;
for(i = 0, j = 0; i < (length); i++, j = j + 2)
{
result[j] = s1[i];
result[j + 1] = s2[i];
}
return result;
}
For the values of S1 and S2 above it produces:
`H1e2l3l4o5:=C:\Uºt6▄╘º`
Which confuses me as I didn't allocate "result" enough memory for that many chars and wasn't warned of a segmentation fault or anything of that nature. Have I obviously done something wrong?
This happens because you did not null-terminated the string in the result. Add this line to fix this problem:
result[j] = '\0';
Another issue you need to fix is allocating the space for null terminator:
char* result = malloc(length * 2 + 1);
C standard requires sizeof(char) to be 1, so multiplying by it is not necessary.
Finally, you need to make sure that s2 has enough length to be copied into the result, i.e. strlen(s2) >= strlen(1).
You didn't allocate memory for the null character required to terminate a C string and, of course, you didn't put it after the string. This is why the code prints garbage from memory until it reaches the first null character.
char* mix(char *s1, char *s2)
{
int length = strlen(s1);
char* result = malloc(sizeof(char) * (length * 2 + 1));
int i, j;
for(i = 0, j = 0; i < length; i ++, j = j + 2)
{
result[j] = s1[i];
result[j + 1] = s2[i];
}
// Put the null character to end the the string
result[j] = 0;
return result;
}
Apparently the code should also check the length of s2 but, by chance, this is not needed.
If s1 is longer than s2, the null-terminating character of s2 is copied during the loop and the length of the resulting string is 2*strlen(s2). If s2 is longer than s1, the code copies only its first length characters.
I want to concatenate two strings without using strcat() function.But I am not getting the required result. Please point me my mistake.
void main() {
char s1[100], s2[100];
int i;
puts("First string?");
gets(s1);
puts("Second string?");
gets(s2);
for (i = strlen(s1); i <= (strlen(s1) + strlen(s2)); i++) {
s1[i] = s2[i - strlen(s1)];
}
puts(s1);
}
I didn't really change much in your program, but here's what I have (modified from yours) and it works.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char s1[100], s2[100];
size_t i, s1l, s2l, total;
puts("First string?");
fgets(s1, sizeof(s1), stdin);
s1[strlen(s1) - 1] = 0x00;
puts("Second string?");
fgets(s2, sizeof(s2), stdin);
s2[strlen(s2) - 1] = 0x00;
s1l = strlen(s1);
s2l = strlen(s2);
total = s1l + s2l;
for(i = s1l; i <= total; i++)
{
s1[i] = s2[i - s1l];
}
puts(s1);
return(0);
}
Using your program verbatim, the problem was that since the length of s1 was changing at each iteration of the loop, the strlen(s1) in the check kept increasing in value so you would basically end up with a mostly infinite loop...at least until it encountered some random null byte. However, when taking the length of the strings before hand, the loop terminus count does not change which results in the proper output. My code will compile and run correctly on a FreeBSD 10.2 system using the clang compiler.
As a side note, DO NOT return void on main. ALWAYS return int. Also specify the library headers that you plan to use.
EDIT: I modified the code to use fgets instead of gets since gets is completely unsafe. It does not check buffer sizes so you can easily have a buffer overflow.
The length of s1 is getting changed at runtime, making your index i incorrect. Try something like below:-
l = strlen(s1);
for(i = 0; i < strlen(s2); i++)
{
s1[l++] = s2[i];
}
s1[l] = '\0';
Suppose s1 = "hello" and s2 = "world", then in the first iteration length of s1 = 5 and index for s2 = 0(i- length(s1)); works well. But in the second iteration length(s1) = 6 and index for s2 = 0(i-length(s1)). so index for taking the character from s2 is not changing. This was about the problem in your implementation, though you should an efficient way by using sprintf.
sprintf(s1, "%s%s", s1, s2);
Use a variation of sprintf:
simpler
char buf[200];
sprintf(buf, "%s%s" s1, s2);
simpler and safer
char buf[200]
snprintf(buf, sizeof(buf), "%s%s", s1, s2);//prevents buffer overflow
Or, modify your loop (see in line comments for why):
int main(void)//note changed main prototype
{
char s1[100], s2[100];//caution here: s1 must be big enough
//to contain its string as well as
//the string stored in s2, plus 1 for NULL
int i;
int len1, len2;//create variables to store string lengths
puts("First string?");
gets(s1);//note, gets is no longer recommended
puts("Second string?");
gets(s2);
len1 = strlen(s1);//store string lengths only once
len2 = strlen(s2);//to avoid calling them repeatedly in loop
for(i = 0; i < len2; i++)//index i in one place only
{
s1[len1+i] = s2[i];
}
s1[len1 + i]=0;//null terminate string when done.
puts(s1);
getchar();//added to pause execution in my environment.
return 0;
}
A sample session using the above modifications is shown here:
Your solution does not work because you recompute strlen(s1) upon each iteration to test for completion and to figure the offset in s2 to copy a character from, but you modify s1 in the loop, so the length changes, and even worse, s1 is temporarily no longer '\0' terminated: the test expression i <= strlen(s1) + strlen(s2) invokes undefined behavior, and the same happens when you copy s2[i - strlen(s1)] the second time through the loop.
Use these ideas to correct your code:
do not use gets to read input, use fgets() and remove the final '\n'.
compute the length of s1 and s2 only once and store them in local variables.
verify that the concatenation will not exceed the size of s1.
rewrite your loop with these local variables, or use strcpy or memcpy.
Here is an example:
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[100], s2[100];
size_t i, len1, len2;
puts("First string?");
if (!fgets(s1, sizeof s1, stdin))
return 1;
len1 = strlen(s1);
if (len1 > 0 && s1[len1 - 1] == '\n')
s1[--len1] = '\0';
puts("Second string?");
if (!fgets(s2, sizeof s2, stdin))
return 1;
len2 = strlen(s2);
if (len2 > 0 && s2[len2 - 1] == '\n')
s1[--len2] = '\0';
if (len1 + len2 >= sizeof s1)
return 2;
/* copy the characters from s2 including the final '\0' */
for (i = 0; i <= len2; i++) {
s1[len1 + i] = s2[i];
}
puts(s1);
return 0;
}
// A simple strcat function
int main(void)
{
char str1[100] ="Avis";
stringcat(str1,"karthik");
printf("\n%s",str1);
return 0;
}
void stringcat(char *str1, char *str2)
{
while(*str1)
str1++;
while(*str2)
*str1++ = *str2++;
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C String Concatenation
How do I concatenate multiple char strings in C ?
Example:
const char *bytes = "tablr=Hello%20World";
const char *bytes2 = "tablr=Hello%20World";
const char *bytes3 = "tablr=Hello%20World";
thanks
Here's a suggestion, that avoids the Painter's problem:
char const *bytes = "tablr=Hello%20World";
char const *bytes2 = "tablr=Hello%20World";
char const *bytes3 = "tablr=Hello%20World";
unsigned int const sz1 = strlen(bytes );
unsigned int const sz2 = strlen(bytes2);
unsigned int const sz3 = strlen(bytes3);
char *concat = (char*)malloc(sz1+sz2+sz3+1);
memcpy( concat , bytes , sz1 );
memcpy( concat+sz1 , bytes2 , sz2 );
memcpy( concat+sz1+sz2 , bytes3 , sz3 );
concat[sz1+sz2+sz3] = '\0';
/* don't forget to free(concat) when it's not needed anymore */
This avoids the painter's problem and should be more efficient (although sometimes not) because memcpy may copy byte-by-byte or word-by-word, depending on the implementation, which is faster.
If you can see a pattern here, this can easilly be transformed into a function that concatenates an arbitrary number of strings, if they are provided in an char const*[]
String literals can be concatenated simply by being adjacent:
const char *whole_string = "tablr=Hello%20World" "tablr=Hello%20World" "tablr=Hello%20World";
The above concatenation is done by the compiler and doesn't incur runtime overhead.
In general, you use the strcat function declared in <string.h>.
But you can concatenate string literals merely by writing them one after another. Example:
const char *p = "Hello, " "World"
"!";
p points to "Hello, World!".
In your case it would be like this:
const char* p =
"tablr=Hello%20World"
"tablr=Hello%20World"
"tablr=Hello%20World";
With string.h included (the easy but "slow" (not really very slow ;P) way):
char * result = calloc(strlen(bytes)+strlen(bytes2)+strlen(bytes3)+1,sizeof(char));
strcat(result, bytes);
strcat(result, bytes2);
strcat(result, bytes3);
Using an efficient loop:
int i, j, len = strlen(bytes)+strlen(bytes2)+strlen(bytes3)+1;
char * result = malloc(sizeof(char)*len);
for(i = 0; i < len && bytes[i] != '\0'; i++)
result[i] = bytes[i];
for(j = 0; i < len && bytes2[j] != '\0'; i++, j++)
result[i] = bytes2[j];
for(j = 0; i < len && bytes3[j] != '\0'; i++, j++)
result[i] = bytes3[j];
result[i] = '\0';
Use the strcat or strncat functions. Be careful with the memory allocations around those though.
If your compiler supports it use strcat_s or _tcscat_s. They will check the buffer length you're writing to.
I suggest to use memcpy function. It is quite efficient:
int l1 = strlen(bytes), l2 = strlen(bytes2), l3 = strlen(bytes3);
int length = l1+l2+l3;
char *concatenatedBytes = (char *)malloc((length+1)*sizeof(char));
memcpy(concatenatedBytes, bytes, l1);
memcpy(concatenatedBytes + l1, bytes2, l2);
memcpy(concatenatedBytes + l1 + l2, bytes3, l3);
concatenatedBytes[length] = 0;