I am attempting to complete a homework assignment, part of which is to design a function that inserts a string into another string. All functions, with the exception of strlen(), are off limits to me. Specifically the problem is this: I am having trouble implementing the part of the function that "makes room" in the target string for the inserted string. Inserting the string always results in a trampling of array elements. Can anyone point out what I am doing wrong here? Thanks for helping me learn!
Edit: Integer n is the location in the string that I am supposed to insert the other string.
void insertstring(char *str, char *ins, int n)
{
int i;
int scoot=strlen(ins);
char *p=str+n;
for (i=strlen(str); i > n; --i) { //This is where I'm doing it wrong I think
str[i+scoot]=str[i]; //
}
do {
*p = *ins;
++p;
++ins;
}
while (*ins != '\0');
}
An elegant solution uses reversing to achieve the desired result. Assume your target string, str, is composed of two blocks, AB, where A is the block before the insertion point, and B is the block after insertion point. Furthermore, assume that the string to insert, ins, is denoted by a third block C.
It can be seen that if you concatenate C to AB and then reverse B, reverse C, and reverse both B and C, you get ACB, which is the desired result. More explicitly, this is what you have after appending C to AB:
ABC
And this is what you want:
ACB
ACB can be obtained by:
Reverse B, to get B_r (B reversed);
Reverse C, to get C_r - at this point we have AB_rC_r;
Reverse both B and C, that is, compute A(B_rC_r)_r, which yields ACB.
Here's the code that implements this algorithm:
void reverse(char *, char *, char *);
/* Insert string C between blocks AB in str */
void insertstring(char *str, char *ins, int n) {
/* 1 - Append C to the end of str */
int i = strlen(str);
char *p = str+i, *q = ins;
while ((*p++ = *q++));
p--;
/* 2 - Reverse C and B */
reverse(str, str+i, p-1); /* C */
reverse(str, str+n, str+i-1); /* B */
/* 3 - Reverse B_rC_r */
reverse(str, str+n, p-1);
}
void reverse(char *str, char *begin, char *end) {
char tmp;
while (begin < end) {
tmp = *begin;
*begin = *end;
*end = tmp;
begin++;
end--;
}
}
And some sample code to test it:
#include <stdio.h>
#include <string.h>
int main() {
void insertstring(char *, char *, int);
char test[128] = "A string to test.";
printf("Before: %s\n", test);
insertstring(test, "hello!", 4);
printf("After: %s\n", test);
return 0;
}
This will insert "hello!" beginning in test[4]. Here's the output:
$ ./test
Before: A string to test.
After: A sthello!ring to test.
Consider taking this approach: the code is short and elegant. This technique is described in Programming Pearls, 2nd edition, as a good way to perform vector rotation. According to the author, Brian Kernighan and P.J. Plauger used precisely this method in their Software Tools in Pascal to move lines within a text editor.
First you have change
for (i=strlen(str); i > n; --i)
to
for (i=strlen(str); i >= n; --i)
because you have to move str[n] too.
The other problem is when you insert ins:
do {
*p = *ins;
++p;
++ins;
}
while (*ins != '\0');
Here you copy the terminating '\0' from ins to str so the rest is lost. Change it to
while (*ins != '\0') {
*p = *ins;
++p;
++ins;
}
After mentioning about n, update for loop as
for (i=n+scoot; i >= n; i--)
You want to move strlen(ins) number of character ahead from location n.
Tried it with single loop,
go to index , copy src content into temp_array and simultaneously copying medi into src
once medi is copied completely , start putting the content of temp_array till it become empty
void insert_in_middle (char *src, char *medi, int index)
{
int i=0, j = index, k=0;
char temp_array[50];
while(src[j] != '\0' || temp_array[k] != '\0')
{
temp_array[i] = src[j];
if(medi[i] != '\0')
{
src[j] = medi[i];
}
else if(temp_array[k] != '\0')
{
src[j] = temp_array[k];
k++;
}
i++; j++;
}
printf("src[%s]\n", src);
printf("medi[%s]\n",medi);
printf("temp_array[%s]\n",temp_array);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *str_ins();
int main()
{
char *test = "Hello, world!";
printf("%s\n",test);
str_ins(&test,strstr(test,"world"),"my ");
printf("%s\n",test);
}
char *str_ins(a, b, c) // insert string c into a at point b
char **a, *b, *c;
{
char *stemp;
int pos = strlen(*a) - strlen(b);
stemp = (char *) malloc(strlen(*a)+strlen(c)+1);
strncpy(stemp,*a,pos);
strcpy(stemp+pos,c);
strcat(stemp,b);
free(a);
*a = stemp;
return *a;
}
Related
So I've looked around on SO and can't find code that answers my question. I have written a function that is supposed to reverse a string as input in cmd-line. Here is the function:
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string)];
for (x = strlen(string) - 1; x > 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
string = line;
}
When I call my reverse() function, the string stays the same. i.e., 'abc' remains 'abc'
If more info is needed or question is inappropriate, let me know.
Thanks!!
You're declaring your line array one char shorter remember the null at the end.
Another point, it should be for (x = strlen(string) - 1; x >= 0; x--) since you need to copy the character at 0.
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string) + 1];
for (x = strlen(string) - 1; x >= 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
for(x = 0; x < strlen(string); x++)
{
string[x] = line[x];
}
}
Note that this function will cause an apocalypse when passed an empty string or a string literal (as Bobby Sacamano said).
Suggestion you can probably do: void reverse(char source[], char[] dest) and do checks if the source string is empty.
I think that your answer is almost correct. You don't actually need an extra slot for the null character in line. You just need two minor changes:
Change the assignment statement at the bottom of the procedure to a memcpy.
Change the loop condition to <-
So, your correct code is this:
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string)];
for (x = strlen(string) - 1; x >= 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
memcpy(string, line, sizeof(char) * strlen(line));
}
Since you want to reverse a string, you first must decide whether you want to reverse a copy of the string, or reverse the string in-situ (in place). Since you asked about this in 'C' context, assume you mean to change the existing string (reverse the existing string) and make a copy of the string in the calling function if you want to preserve the original.
You will need the string library
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Array indexing works, and this version takes that approach,
/* this first version uses array indexing */
char*
streverse_a(char string[])
{
int len; /*how big is your string*/
int ndx; /*because 'i' is hard to search for*/
char tmp; /*hold character to swap*/
if(!string) return(string); /*avoid NULL*/
if( (len=strlen(string)) < 2 ) return(string); /*one and done*/
for( ndx=0; ndx<len/2; ndx++ ) {
tmp=string[ndx];
string[ndx]=string[len-1-ndx];
string[len-1-ndx]=tmp;
}
return(string);
}
But you can do the same with pointers,
/* this is how K&R would write the function with pointers */
char*
streverse(char* sp)
{
int len, ndx; /*how big is your string */
char tmp, *bp, *ep; /*pointers to begin/end, swap temporary*/
if(!sp) return(sp); /*avoid NULL*/
if( (len=strlen(bp=sp)) < 2 ) return(sp); /*one and done*/
for( ep=bp+len-1; bp<ep; bp++, ep-- ) {
tmp=*bp; *bp=*ep; *ep=tmp; /*swap*/
}
return(sp);
}
(No, really, the compiler does not charge less for returning void.)
And because you always test your code,
char s[][100] = {
"", "A", "AB", "ABC", "ABCD", "ABCDE",
"hello, world", "goodbye, cruel world", "pwnz0r3d", "enough"
};
int
main()
{
/* suppose your string is declared as 'a' */
char a[100];
strcpy(a,"reverse string");
/*make a copy of 'a', declared the same as a[]*/
char b[100];
strcpy(b,a);
streverse_a(b);
printf("a:%s, r:%s\n",a,b);
/*duplicate 'a'*/
char *rp = strdup(a);
streverse(rp);
printf("a:%s, r:%s\n",a,rp);
free(rp);
int ndx;
for( ndx=0; ndx<10; ++ndx ) {
/*make a copy of 's', declared the same as s[]*/
char b[100];
strcpy(b,s[ndx]);
streverse_a(b);
printf("s:%s, r:%s\n",s[ndx],b);
/*duplicate 's'*/
char *rp = strdup(s[ndx]);
streverse(rp);
printf("s:%s, r:%s\n",s[ndx],rp);
free(rp);
}
}
The last line in your code does nothing
string = line;
Parameters are passed by value, so if you change their value, that is only local to the function. Pointers are the value of the address of memory they are pointing to. If you want to modify the pointer that the function was passed, you need to take a pointer to that pointer.
Here is a short example of how you could do that.
void reverse (char **string) {
char line = malloc(strlen(*string) + 1);
//automatic arrays are deallocated once the function ends
//so line needs to be dynamically or statically allocated
// do something to line
*string = line;
}
The obvious issue with this is that you can initialize the string with static memory, then this method will replace the static memory with dynamic memory, and then you'll have to free the dynamic memory. There's nothing functionally wrong with that, it's just a bit dangerous, since accidentally freeing the string literal is illegal.
char *test = "hello";
reverse(test);
free(test); //this is pretty scary
Also, if test was allocated as dynamic memory, the pointer to it would be lost and then it would become a memory leak.
I have created a function for strend, which basically returns 1 if string t is present at the end of string s, however it never returns 1:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int strend(char *s, char *t) {
int p;
for (p = 0; p < strlen(s) - strlen(t); p++) {
*s++;
}
printf("%s\n%s\n", s, t);
if (s == t)
return 1;
return 0;
}
int main(void) {
int bool = strend("Hello", "ello");
printf("%i\n", bool);
return 0;
}
This gives me an output of:
ello
ello
0
So technically I should get 1. I assume the comparison using pointers is not used in this way?
You need to review your basic knowledge of C strings. There are lots of standard string functions in string.h that can help you with this test.
The basic problem is that the test s == t is valid, but you are comparing memory addresses here. You can see that is valid if you change the strings to test to
char test[] = "Hello";
int bool = strend_(test, test+1);
where test obviously is the same as your "Hello", and similarly, test+1 is the same as "ello" (try it by printing them). This correctly returns 1 with your routine.
In addition, I get two warnings:
on *s++; "warning: expression result unused [-Wunused-value]": you increment s but also ask what character is at that position through *s; and you don't use that information.
Fix by removing the * there.
on p < strlen(s) ..; "warning: comparison of integers of different signs: 'int' and 'unsigned long'", because strlen does not return a signed integer but an unsigned one (apparently, my header uses unsigned long).
Fix by declaring p as unsigned long, or even better, size_t.
Your entire routine can be condensed to a simple
int strend (char *s, char *t)
{
if (strlen(s) >= strlen(t) && !strcmp (s+strlen(s)-strlen(t),t))
return 1;
return 0;
}
It's not worth the trouble to cache the result of those four strlen calls into 2 temporary variables; a good compiler will work it out and do that for you. (A quick glance to the assembly output of the compiler I'm using – clang – shows it does, even with the default optimization settings.)
A slightly modified test, based on #M.M.'s comment:
int strend (char *s, char *t)
{
if (strlen(s) < strlen(t)) return 0;
return !strcmp (s+strlen(s)-strlen(t),t);
}
but attempting to optimize it this way is not as easy parsed as the routine above, and its assembly is ever so slightly "wordy" as well. Personally, I'd go for the more humanly readable version.
Use strcmp(3)
if (strcmp(s, t) == 0) return 1;
This actually compares the contents of the memory pointed to by s and t rather than their addresses.
Your code is broken in multiple ways:
The initial loop is a very cumbersome way to advance p by the difference of lengths if positive.
Once you have pointers at the same distance from the end of both strings, You should compare the characters with strcmp() (or memcmp() if you can first exclude the case of strlen(s) < strlen(t).
Comparing the pointers obtained after the loop will only work if t points inside the string pointed to by s, a special case that may or may not be produced by the compiler for the specific call in main: strend("Hello", "ello");.
Here is a modified version:
#include <string.h>
int strend(const char *str1, const char *str2) {
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
return len1 >= len2 && !memcmp(str1 + len1 - len2, str2, len2);
}
I corrected/modified your code, here is the code,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#pragma warning(disable:4996)
int strend(char *s, char *t)
{
int p,flag=0,count=0;//count will be the starting index for *t
p = strlen(s) - strlen(t);//this will be the starting index for *s
while(count<strlen(t))
{
if (*(s+p) == *(t+count))
{
flag = 1;
count++;
p++;
continue;
}
else
{
flag = 0;
break;
}
}
return flag;
}
int main(void)
{
int flag = strend("Hello", "ello");
printf("%i\n", flag);
return 0;
}
This code works too.
#include <stdio.h>
#include <string.h>
int strend (char *s1, char *s2);
void main ()
{
char str1[20] = "somethings";
char str2[20] = "things";
int f;
f = strend (str1,str2);
if (f==1)
printf ("1");
else
printf ("0");
}
int strend (char *str1, char *str2)
{
int l = strlen(str1) - strlen(str2);
str1 = str1 + l;
int d = strcmp(str1,str2);
if (d == 0)
return 1;
else
return 0;
}
this code works well.
int strend(char *s, char *t){
while(*t & *s){
if(*t == *s){
t++;
}
s++;
}
return *t==*s;
}
i'm trying to reverse a string using recursion and a single pointer to that string.
My idea is to traverse the string from both edges, raising the pointer and inserting '\0's at the end of the string. For example - given a string 'abcde\0' - replace "chars" before the middle of the string, and insert '\0' after -> recursive calls -> when "stop condition" is reached, original string should be like this - 'edc\0\0\0' - and half of chars stored as temp variable, in stack. When turning back and popping the stack, these chars should overwrite the '\0' in reverse order. This is the idea.
This is my code so far, but I can't get it work - please help me understand, what do I miss. I have a '\0' in the middle of string that I can't figure out how to rewrite it. (I guess this is the major problem)
Thanks in advance.
#include <stdio.h>
#include <string.h>
void rev_str(char* _str);
int main()
{
char str[]="abcde";
puts("Str before:");
puts(str);
rev_str(str);
puts("Str after");
puts(str);
return 0;
}
void rev_str(char* _str)
{
int len=strlen(_str);
char temp=*_str;
if(len>1)
{
*_str = _str[len-1];
_str[len-1]='\0';
rev_str(++_str);
}
_str[len-1]=temp;
}
I won't debug your code, however this might help you understand things better -
http://www.programmingsimplified.com/c-program-reverse-string
Examples taken from page -
C program to reverse a string using pointers
Now we will invert string using pointers or without using library function strrev.
#include<stdio.h>
int string_length(char*);
void reverse(char*);
main()
{
char string[100];
printf("Enter a string\n");
gets(string);
reverse(string);
printf("Reverse of entered string is \"%s\".\n", string);
return 0;
}
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
length = string_length(string);
begin = string;
end = string;
for (c = 0; c < length - 1; c++)
end++;
for (c = 0; c < length/2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
int string_length(char *pointer)
{
int c = 0;
while( *(pointer + c) != '\0' )
c++;
return c;
}
C program to reverse a string using recursion
#include <stdio.h>
#include <string.h>
void reverse(char*, int, int);
int main()
{
char a[100];
gets(a);
reverse(a, 0, strlen(a)-1);
printf("%s\n",a);
return 0;
}
void reverse(char *x, int begin, int end)
{
char c;
if (begin >= end)
return;
c = *(x+begin);
*(x+begin) = *(x+end);
*(x+end) = c;
reverse(x, ++begin, --end);
}
rev_str(++_str);
This is the problem. You're modifying _str here so when you do _str[len-1]=temp at the end, you're writing to the wrong location. Change it to
rev_str(_str + 1);
Just change the code rev_str(++_str); into rev_str(_str+1);. The ++_str equal to _str += 1, it will change the pointer char *_str. But _str+1 will only initialize the formal param, and will not change the 'char *str'. I hope this can help you.
I'm trying to mimic a sample program given in K&R, which looks like this:
void strcat(char s[], char t[])
{
int i, j;
i = j = 0;
while (s[i] != '\0') /* find end of s */
i++;
while ((s[i++] = t[j++]) != '\0') /* copy t */
;
}
I want to do the same thing, except that, instead of appening t to s, I'd like to copy both into a new string. My try is as follows :
#include <stdio.h>
#include <string.h>
void concat
(const char lstr[], const char rstr[], char outstr[])
{
int i, j;
i = j = 0;
while (lstr[i] != '\0')
outstr[i++] = lstr[i++];
while ((outstr[i++] = rstr[j++]) != '\0')
;
}
int main(void)
{
char lword[] = "foo";
char rword[] = "bar";
char outword[strlen(lword) + strlen(rword)];
concat(lword, rword, outword);
printf("%s\n", outword);
}
However, the above only prints garbage (I mean f�����bar). I can't find out where the error lies.
Two problems:
No space for terminating null character in outword. Needs to be:
char outword[strlen(lword) + strlen(rword) + 1];
/*^^^*/
This is undefined behaviour as i is being modified twice in the same statement:
outstr[i++] = lstr[i++];
/* Change to: */
while (lstr[i] != '\0')
{
outstr[i] = lstr[i];
++i;
}
With these two changes the program produces a new concatenated string (http://ideone.com/9QbU0q).
Every string in C needs to end with a null character, which won't be visible. It does however need to be accounted for in the size of the memory you allocate.
When copying lstr to outstr you're incrementing your index twice. Use outstr[i] = lstr[i++]
I am currently studying C and I can't get past this exercise. I must create a recursive function to reverse string1 into string2. Here is my code. I would gladly appreciate your help.
#include <stdio.h>
#define MAX 100
void reverse(char s1[],char s2[],int n,int j);
int main()
{
char string1[MAX]="How Are You Mate";
char string2[MAX]="";
int n=0;
int i=0;
int j=0;
for(i=0;string1[i]!='\0';i++)
n++;
reverse(string1,string2,n,j);
printf("String-a normal:\n%s\n",string1);
printf("String-a reverse:\n%s\n",string2);
return 0;
}
void reverse(char s1[],char s2[],int n,int j)
{
if(n>0)
{
s2[j]=s1[n];
reverse(s1,s2,n-1,j+1);
}
else
s2[j]='\0';
}
in-place (the caller could make a copy of the string before calling this function) string reverse with tail-recursion
void reverse (char *str, size_t len)
{
char tmp;
if (len-- < 2) return;
tmp = *str;
*str = str[len];
str[len] = tmp;
reverse (str+1, len -1);
}
O, if you don't want pointers:
void reverse (char str[], size_t len)
{
char tmp;
if (len-- < 2) return;
tmp = str[0];
str[0] = str[len];
str[len] = tmp;
reverse (str+1, len -1);
}
The reversing starts by copying the n-th character of string1 array into string2. The n-th character happens to be the null terminator. It becomes the first character of your new string, so the string looks empty to all standard C routines, including printf.
Calling
reverse(string1,string2,n-1,j);
from the main should fix the problem. The condition in the reverse should be changed from if(n>0) to if(n>=0) as well.
Although it does not save the resulting string anywhere, you get the idea.
#include <stdio.h>
void rev (const char* str);
int main () {
const char str[] = "!dlrow ,olleH";
printf("%s\n", str);
rev(str);
printf("\n");
return 0;
}
void rev (const char* str) {
char c = *str;
if (c != '\0') {
rev(str + 1);
printf("%c", c);
}
}
I have corrected the program. Please find the changes below
void reverse(char s1[],char s2[],int n,int j)
{
if(n>0)
{
s2[j]=s1[n-1];
reverse(s1,s2,--n,++j);
}
else
s2[j]='\0';
}
i recommend using library , size=strlen(array) in stead of
for(i=0;string1[i]!='\0';i++)
n++;
to count how many characters in arra