I have created two arrays that need to be concatenated after the second array (y in this case) has been rotated. However I want to rotate only the last 4 bytes of this array. This is my code:
char x[]={"hello"};
char y[]={"goodmorning"};
char combine[20];
strcpy(combine, x);
strcat(combine, y);
printf(combine);
Here before the concatenation into combine I want to do the rotation operation.
before rotation
combine= hellogoodmorning
after rotation
combine= gninhellogoodmor
I have tried to look for a logic to do this online but could not find anything specific. Can anybody please help.
void strRev(char *s)
{
char temp, *end = s + strlen(s) - 1;
while( end > s)
{
temp = *s;
*s = *end;
*end = temp;
--end;
++s;
}
}
char x[]={"hello"};
char y[]={"goodmorning"};
char combine[20];
strcpy(combine, x);
strcat(combine, y);
strRev(combine);
strRev(combine+4);
printf(combine);
I use
#define swap(a, b) { a ^= b; b ^= a; a ^= b; }
void reverse(char * s, int beg, int end) {
while (beg < end) {
swap(s[beg], s[end]);
++beg, --end;
}
}
void rotate(char * s, int k) {
if (!s || !*s) return;
int len = strlen(s);
k %= len;
reverse(s, 0, len - 1);
reverse(s, 0, k - 1);
reverse(s, k, len - 1);
}
and call rotate(combine, 4); to rotate 4 bytes in combine.
Try something like this shown below. I use strncpy instead of strcpy() and strcat(). Try to debug for better understanding. Run Live.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROTATION_LEN 4
int main() {
char x[] = { "hello" };
char y[] = { "goodmorning" };
char c;
char combine[20] = {0}; // init with null
char * com = combine;
int i;
int leny = strlen(y);
int lenx = strlen(x);
for (i = 0; i < ROTATION_LEN; ++i) {
c = y[leny -1 - i];
combine[i] = c;
}
com += ROTATION_LEN; // forward address of combine by ROTATION_LEN
strncpy(com, x, lenx);
com += lenx; // forward address of combine by x length
strncpy(com, y, leny - ROTATION_LEN);
printf(combine);
return 0;
}
Output:
gninhellogoodmor
If you define a function like this:
void rotate_last_four(char *string)
{
char old_four[4];
char new_four[4];
strncpy(old_four, string + strlen(string) - 4, 4);
new_four[0] = old_four[3];
new_four[1] = old_four[2];
new_four[2] = old_four[1];
new_four[3] = old_four[0];
memmove(string + 4, string, strlen(string) - 4);
strncpy(string, new_four, 4);
}
Then you only need to add this line to your code before printing combine:
rotate_last_four(combine);
And the output is: gninhellogoodmor
Related
How can I merge character by character two strings of different sizes to the n-th element of A and m-th element of B. I can easily do it when they have the same size (assuming here n=m). But cannot figure out how to handle this exception.
My working zip code is as follows:
char * zip(char *A, char *B, int n)
{
char *C;
int i;
C = malloc((2*n) * sizeof *A);
for(i=0; i<n; i++) {
C[(2*i)]=A[i];
C[(2*i)+1]=B[i];
}
return C;
}
But instead to pass just int n, I would like to pass also int m where n is to merge the n first elements of A and the m first elements of B. Hence passing the following input to the new_zip(char *A, char *B, int n, int m). A="rslxyzkw"; B="eutingxyz";n=3; m=6, I would get "resulting".
like this:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *new_zip(char *A, char *B, int n, int m){
assert(A != NULL && B != NULL && n >= 0 && m >= 0);
char *C = malloc(n + m + 1);//+1 for NUL
if(!C){
perror("malloc:");
return NULL;
}
int i = 0;
while(n + m > 0){
if(n > 0 && *A){
C[i++] = *A++;
--n;
}
if(m > 0 && *B){
C[i++] = *B++;
--m;
}
}
C[i] = 0;
return C;
}
int main (void){
char *result = new_zip("rslxyzkw", "eutingxyz", 3, 6);
printf("'%s'\n", result);
free(result);
return 0;
}
Instead of looping until a certain length you can loop until you run out of characters. C strings have a null character at the end so after you allocate the memory you can loop as long as both aren't a null character. All you need to do then is only add non-null characters to your output string.
#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* strlen */
char *zip(char *a, char *b)
{
char *c = malloc( (strlen(a)+strlen(b)+1) * sizeof(char) ), *p = c;
if(c)
{
while(*a || *b) /* while either string has characters */
{
if(*a) *p++ = *a++; /* add a character from a if non-null */
if(*b) *p++ = *b++; /* add a character from b if non-null */
}
*p='\0'; /* finish the string with a null character */
}
return c;
}
int main()
{
char *a = "This is a string";
char *b = "This is another longer string";
char *c = zip(a,b);
if(c)
{
printf("zip(%s,%s) = %s\n",a,b,c);
free(c);
}
return 0;
}
The following could work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* zip(char* A, char* B) {
char *C;
int k = 0;
C = (char*)malloc(strlen(A)+strlen(B)+1);
while (*A != '\0' || *B != '\0') {
if (*A != '\0') {
C[k++] = *A;
++A;
}
if (*B != '\0') {
C[k++] = *B;
++B;
}
}
C[k] = '\0';
return C;
}
int main() {
char *A = "123456", *B = "abcd", *C;
C = zip(A, B);
puts(C);
return 0;
}
The below code would work in the following way:
First do alternate merging from strings s1 and s2 based on the minimum value of m and n.
The second part would take care of appending the remaining elements either from s1 or from s2.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* merge (char *s1, char *s2, int m, int n)
{
char *s = (char *) malloc(m + n + 1);
int min = (m < n)? m: n;
int i = 0, j = 0, k = 0;
int count = 0;
/* Alternate merge from s1 and s2 to s*/
while (count < 2 * min) {
if (count % 2 == 0) {
s[k++] = s1[i++];
} else {
s[k++] = s2[j++];
}
count++;
}
/* Append the remaining elements from s1 or s2 to s*/
if (m > min) {
for (count = 0; count < m - min; count++) {
s[k++] = s1[i++];
}
} else if (n > min) {
for (count = 0; count < n - min; count++) {
s[k++] = s2[j++];
}
}
s[k++] = '\0';
return s;
}
int main()
{
char *s1 = "rslxyzkw";
char *s2 = "eutingxyz";
char *s = merge(s1, s2, 3, 6);
printf ("%s\n", s);
}
I tried to write code using strrev(). I included <string.h> but still I'm getting an "undefined reference to strrev" error.
I found that strrev() doesn't have man page at all. Why?
Doesn't Linux support strrev()?
Correct. Use one of the alternative implementations available:
#include <string.h>
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
#include <string.h>
char *strrev(char *str)
{
if (!str || ! *str)
return str;
int i = strlen(str) - 1, j = 0;
char ch;
while (i > j)
{
ch = str[i];
str[i] = str[j];
str[j] = ch;
i--;
j++;
}
return str;
}
To accurately answer your question,
Is strrev() not available on Linux?
The functions strrev() available in the string.h library. Functions strrev() including some other string functions such as like strupr(), strlwr(), strrev(), which are only available in ANSI C (Turbo C/C++) and are not available in the standard C-GCC compiler.
It’s not about the system. It is about the C compiler you are using.
References:
https://discuss.codechef.com/t/is-strrev-function-not-available-in-standard-gcc-compiler/2449
https://www.csestack.org/undefined-reference-to-strrev/
Unfortunately, strrev seems to be absent from glibc's string.h.
Obviously, I'm late to the here's-some-code party, but I like this implementation.
#define MAX_CHARS 10000
// safe_usub -- perform safe unsigned subtraction
size_t safe_usub (size_t x, size_t y) {
return x > y ? x - y : y - x ;
}
char* str_reverse (const char* const str) {
if (!str) { return NULL; }
size_t len = strnlen(str, MAX_CHARS);
char* new = malloc( sizeof(char) * len );
size_t i;
for (i = 0; i < len; i++) {
new[i] = str[ safe_usub(i + 1, len) ];
}
new[i] = 0;
return new;
}
How about this:
#include <string.h>
char *strrev(char *s)
{
if (s && *s) {
char *b = s, *e = s + strlen(s) - 1;
while (b < e) {
char t = *b;
*b++ = *e;
*e-- = t;
}
}
return s;
}
There is no string library function to reverse a string.
strrev() Is not present in GCC compiler in Linux.
Make your own reverse function:
reverse.c:
/*
* C program to reverse a string using recursion
*/
#include <stdio.h>
#include <string.h>
void reverse(char [], int, int);
int main()
{
char str1[20];
int size;
printf("Enter a string to reverse: ");
scanf("%s", str1);
size = strlen(str1);
reverse(str1, 0, size - 1);
printf("The string after reversing is: %s\n", str1);
return 0;
}
void reverse(char str1[], int index, int size)
{
char temp;
temp = str1[index];
str1[index] = str1[size - index];
str1[size - index] = temp;
if (index == size / 2)
{
return;
}
reverse(str1, index + 1, size);
}
Can someone please explain me why I get "Segmentation fault..." and how to fix it on this bit of code?
#include<stdio.h>
int str_length(char *s) {
int length = 0, i;
for(i = 0; *s; i++) {
s++;
}
return i;
}
char *strdel(char *s, int pos, int n) {
int i;
char *p, str[] = "";
p = str;
for(i = 0; i < str_length(s) - n + 1; i++) {
if(i >= pos) {
*(p + i) = *(s + i + n);
}
else {
*(p + i) = *(s + i);
}
}
s = str;
return s;
}
int main() {
char *str = "abcdef";
printf("str_lengh: %d\n", str_length(str));
printf("strdel: %s\n", strdel(str, 1, 2));
return 0;
}
And I get this output:
str_lengh: 6
strdel: adef
Segmentation fault (core dumped)
Also, is there a better way to create a function:
char *strdel(char *s, int pos, int n);
that deletes the n characters from position pos than the one I did?
I think you are writing all over the stack here...
char *strdel(char *s, int pos, int n) {
int i;
char *p, str[] = "";
p = str; // p points to str which is "" and is on the stack with length 0.
for(i = 0; i < str_length(s) - n + 1; i++) {
if(i >= pos) {
*(p + i) = *(s + i + n); // now you are writing onto the stack past p
}
else {
*(p + i) = *(s + i);// now you are writing onto the stack past p
}
}
s = str; // now s points to space on stack
return s; // now you return a pointer to the stack which is about to disapear
}
Whenever you write past p, which is often, you are running into Undefined Behavior. UB
You are writing into space which has not been allocated on the heap or on the stack.
You can write a version of strdel that works only on s. Something like this if I understand strdel right: (roughly, not tested!, needs bounds checking on pos and n )
char *strdel(char *s, int pos, int n) {
char *dst = s + pos, *src = s + pos + n;
while(*src) {
*dst++ = *src++;
}
*dst = 0;
return s;
}
I'll throw in my solution for the second part as well. Here's my strdel
char * strdel(char * s, int pos, int n){
memmove(s + pos, s + pos + n, strlen(s) - pos - n + 1);
return s;
}
It doesn't copy, it doesn't do bounds checking and the return-value is rather redundant (as it's equal to the input s). So all-in-all it's very standard-C-library-like.
Warning! Cannot be used for string-constants as it modifies s (hence no const char * s).
To address the second part of your question, I would have written it something like this (assuming you're going to be passing in string constants and therefore must make a copy of the incoming string):
/*
* Returns a copy of the NUL terminated string at s, with the
* portion n characters long starting at position pos removed.
*/
char* strdel(char* s, int pos, int n)
{
int size = strlen(s);
char* t = malloc(size - n);
memcpy(t, s, pos);
memmove(t + pos, s + pos + n, size - n + 1);
return t;
}
I want to replace the string by index. The string between x and y. If the string that will be replaced the length is lees than y, the pointer must be incremented by the difference. e.g,
given the string ([10 20]...[10 20]..[30 80]); x = 1(index of [) and y = 7(index of ]), and the string-replace is 50, it must be replaced to (50...[10 20]..[30 80]).
I've tried it:
void replaceindex(char *s, char *replace, unsigned int start, unsigned int end)
{
assert(start < end);
char *p = s, *q = s, *r = replace;
register unsigned int i = 0;
int found = 0;
while(*q) {
if(found == 0 && i == start) {
found = 1;
for(; *r; ++r, ++start, ++q)
*p ++ = *r;
while(++start < end)
q++;
}
*p ++ = *q ++;
i ++;
}
}
using:
char str[] = "([10 20]...[10 20]..[30 80])";
printf("Before: %s\n", str);
replaceindex(str, "50", 1, 7);
printf("After: %s\n", str);
The output is:
Before: ([10 20]...[10 20]..[30 80])
After: (500]...[10 20]..[30 80])0])
But I'm expecting this:
Before: ([10 20]...[10 20]..[30 80])
After: (50...[10 20]..[30 80])
How to fix this?
Building on the ideas from Anon ymous, but avoiding the creation of a new string:
void replaceindex(char *s, char *replace, unsigned int start, unsigned int end)
{
unsigned rl, sl;
rl = strlen(replace);
sl = strlen(s);
++end; /* change inclusive index to exclusive one */
assert(start <= end);
assert(rl <= end - start);
memcpy(s + start, replace, rl);
memmove(s + start + rl, s + end, sl - end + 1);
}
You need two fixes:
for(; *r; ++r, ++start, ++q)
*p ++ = *r;
- while(++start < end)
+ while(start++ <= end)
q++;
}
*p ++ = *q ++;
i ++;
}
+ *p = '\0';
}
The first is because your end index is inclusive (judging from the call), and you want to compare first and increment afterwards. The second is to terminate the new string.
Note that you're in serious trouble if strlen(replace) > end - start + 1.
#include <stdio.h>
#include <string.h>
char* replaceindex(char *s, char *replace, unsigned int start, unsigned int end)
{
char *rep= (char*)malloc(strlen(s)+1);
memset(rep,0,strlen(s)+1);
if(strlen(replace)<=(end-start))
{ memcpy(rep,s,start);
memcpy(rep+start,replace,strlen(replace));
memcpy(rep+start+strlen(replace),s+end,strlen(s+end));
return rep;
}
else{free(rep);}
return s;
}
int main() {
char* z="This answer is crazy";
printf("%s",replaceindex(z,"Code",5,11));
return 0;
}
And the Output is
This Code is crazy
EDIT:
Without Memory:-
#include <stdio.h>
#include <string.h>
void replaceindex(char *s, char *replace, unsigned int start, unsigned int end)
{
if(strlen(replace)<=(end-start))
{
char* iter= s+start+strlen(replace),*cursor=s+end;
memcpy(s+start,replace,strlen(replace));
while(*iter)
*iter++=*cursor++;
}
}
int main()
{
char z[]="This answer is crazy";
replaceindex(z,"Code",5,11);
return printf("%s",z);
}
I tried to write code using strrev(). I included <string.h> but still I'm getting an "undefined reference to strrev" error.
I found that strrev() doesn't have man page at all. Why?
Doesn't Linux support strrev()?
Correct. Use one of the alternative implementations available:
#include <string.h>
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
#include <string.h>
char *strrev(char *str)
{
if (!str || ! *str)
return str;
int i = strlen(str) - 1, j = 0;
char ch;
while (i > j)
{
ch = str[i];
str[i] = str[j];
str[j] = ch;
i--;
j++;
}
return str;
}
To accurately answer your question,
Is strrev() not available on Linux?
The functions strrev() available in the string.h library. Functions strrev() including some other string functions such as like strupr(), strlwr(), strrev(), which are only available in ANSI C (Turbo C/C++) and are not available in the standard C-GCC compiler.
It’s not about the system. It is about the C compiler you are using.
References:
https://discuss.codechef.com/t/is-strrev-function-not-available-in-standard-gcc-compiler/2449
https://www.csestack.org/undefined-reference-to-strrev/
Unfortunately, strrev seems to be absent from glibc's string.h.
Obviously, I'm late to the here's-some-code party, but I like this implementation.
#define MAX_CHARS 10000
// safe_usub -- perform safe unsigned subtraction
size_t safe_usub (size_t x, size_t y) {
return x > y ? x - y : y - x ;
}
char* str_reverse (const char* const str) {
if (!str) { return NULL; }
size_t len = strnlen(str, MAX_CHARS);
char* new = malloc( sizeof(char) * len );
size_t i;
for (i = 0; i < len; i++) {
new[i] = str[ safe_usub(i + 1, len) ];
}
new[i] = 0;
return new;
}
How about this:
#include <string.h>
char *strrev(char *s)
{
if (s && *s) {
char *b = s, *e = s + strlen(s) - 1;
while (b < e) {
char t = *b;
*b++ = *e;
*e-- = t;
}
}
return s;
}
There is no string library function to reverse a string.
strrev() Is not present in GCC compiler in Linux.
Make your own reverse function:
reverse.c:
/*
* C program to reverse a string using recursion
*/
#include <stdio.h>
#include <string.h>
void reverse(char [], int, int);
int main()
{
char str1[20];
int size;
printf("Enter a string to reverse: ");
scanf("%s", str1);
size = strlen(str1);
reverse(str1, 0, size - 1);
printf("The string after reversing is: %s\n", str1);
return 0;
}
void reverse(char str1[], int index, int size)
{
char temp;
temp = str1[index];
str1[index] = str1[size - index];
str1[size - index] = temp;
if (index == size / 2)
{
return;
}
reverse(str1, index + 1, size);
}