Overwriting parts of a string with parts of another string - c

I'm trying to overwrite a part of a string with parts of another String.
Basically, I want to access a given index of a string, write a given number of chars from another given index of another string.
So a function like memcpy(stringa[indexa], stringb[indexb], length);, except that this does not work.
Using strncpy would also suffice.
More code, as requested:
void mymemset(char* memloc, char* cmd, int data_blocks[], int len)
{
int i = 0;
while(i < len)
{
//missing part. Where I want the "memcpy" operation to take place
i++;
}
return;
}
memloc is the string we want to overwrite, cmd is the string we are overwriting from, data_blocks contains information about where in memloc we are supposed to write, and len is the number of operations we are executing. So I want to overwrite at location data_blocks[i], from cmd 8 chars at a time.
EDIT: I think I just forgot an &, so sorry to have confused you and thanks for your time. This seems to work:
void mymemset(char* memloc, char* cmd, int data_blocks[], int len)
{
int i = 0;
while(i < len)
{
memcpy(&memloc[data_blocks[i]], &cmd[i*8], 8);
i++;
}
return;
}
Takes 8 bytes at a time from cmd, stores them in memloc at the index given by data_blocks[i]. As commented, data_blocks contains information about different indexes in memloc that is available, and segmentation of the string cmd can occur.

Supposing stringa and stringb are declared as follows
char stringa[] = "Hello" ;
char stringb[] = "World" ;
This should work:
memcpy(&stringa[1], &stringb[1], 2) ;
Your example should not compile, or if it compiles if is likely to crash or to cause undefined behaviour :
memcpy(stringa[1], stringb[1], 2) ;

Your naming is confusing : memset works on bytes. If you manipulate strings you have extra precaution to take: think of the \0.
I think you want something like that:
void my_str_overwrite(char* dest, const char* ref, int idx, size_t count)
{
size_t input_len = strlen(dest);
if(input_len <= idx+count)
{
// Error: not enough space
}
for(size_t i=0; i<count; i++)
{
dest[idx+i] = ref[i];
}
return;
}
You don't need to pass the whole data_block[] array, you just interested in one element of this array which contains an offset for your copy, if I understood correctly.
As you don't modify cmd it should be const
The code above does not handle the NULL terminating byte which should be appended to memloc if it is actually a string
So I want to overwrite at location data_blocks[i], from cmd 8 chars at a time.
This one is confusing. If you know that you only want 8 bytes to be copied each time you call the function then in the code above make count an local variable within the function and fix it size_t count = 8;

if strings are the same size the you can just use memcpy:
#include <strings.h>
char text[] = "Hello James!";
char name[] = "Jenny";
char* pos = strstr(text, "James");
memcpy(pos, name, strlen(name)-1); // for the '\0'
If they're not then you must reallocate the string as the length will change
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define STR "Hello James!"
void replace(char** src, char* find, char* rep) {
char* ret = NULL;
char* pos = strstr(*src, find);
if (!pos)
return; // no changes
int l = (1 + strlen(*src) + strlen(rep) - strlen(find));
ret = (char*)malloc(sizeof(char) * l);
ret[l-1] = 0;
int ind = (int)(pos - *src);
strncpy(ret, *src, ind);
printf("ind: %d; %s\n", ind, ret);
strncpy(&ret[ind], rep, strlen(rep));
strncpy(&ret[ind+strlen(rep)], &pos[strlen(find)], strlen(pos)-strlen(find));
printf("%s\n", ret);
free(*src);
*src = ret;
}
int main() {
char *str = NULL;
str = (char*)malloc(sizeof(char) * (strlen(STR)+1));
assert(str);
strcpy(str, STR);
printf("before: %s\n", str);
replace(&str, "James", "John");
printf("after: %s\n", str);
free(str);
return 0;
}
This code in not optimized.

Related

copy a const char* into array of char (facing a bug)

I have following method
static void setName(const char* str, char buf[16])
{
int sz = MIN(strlen(str), 16);
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = 0;
}
int main()
{
const char* string1 = "I am getting bug for this long string greater than 16 lenght);
char mbuf[16];
setName(string,mybuf)
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Please let me know what is the correct way to code above if the restriction for buf length is 16 in method static void setName(const char* str, char buf[16])
When passing an array as argument, array decays into the pointer of FIRST element of array. One must define a rule, to let the method know the number of elements.
You declare char mbuf[16], you pass it to setName(), setName() will not get char[], but will get char* instead.
So, the declaration should be
static void setName(const char* str, char* buf)
Next, char mbuf[16] can only store 15 chars, because the last char has to be 'null terminator', which is '\0'. Otherwise, the following situation will occur:
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Perhaps this will help you understand:
char str[] = "foobar"; // = {'f','o','o','b','a','r','\0'};
So the code should be
static void setName(const char* str, char* buf)
{
int sz = MIN(strlen(str), 15); // not 16
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = '\0'; // assert that you're assigning 'null terminator'
}
Also, I would recommend you not to reinvent the wheel, why don't use strncpy instead?
char mbuf[16];
strncpy(mbuf, "12345678901234567890", 15);
The following code passes the size of the memory allocated to the buffer, to the setName function.
That way the setName function can ensure that it does not write outside the allocated memory.
Inside the function either a for loop or strncpy can be used. Both will be controlled by the size parameter sz and both will require that a null terminator character is placed after the copied characters. Again, sz will ensure that the null terminator is written within the memory allocated to the buffer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void setName(const char *str, char *buf, int sz);
int main()
{
const int a_sz = 16;
char* string = "This bit is OK!! but any more than 15 characters are dropped";
/* allocate memory for a buffer & test successful allocation*/
char *mbuf = malloc(a_sz);
if (mbuf == NULL) {
printf("Out of memory!\n");
return(1);
}
/* call function and pass size of buffer */
setName(string, mbuf, a_sz);
/* print resulting buffer contents */
printf("%s\n", mbuf); // printed: This bit is OK!
/* free the memory allocated to the buffer */
free(mbuf);
return(0);
}
static void setName(const char *str, char *buf, int sz)
{
int i;
/* size of string or max 15 */
if (strlen(str) > sz - 1) {
sz--;
} else {
sz = strlen(str);
}
/* copy a maximum of 15 characters into buffer (0 to 14) */
for (i = 0; i < sz; i++) buf[i] = str[i];
/* null terminate the string - won't be more than buf[15]) */
buf[i] = '\0';
}
Changing one value const int a_sz allows different numbers of characters to be copied. There is no 'hard coding' of the size in the function, so reducing the risk of errors if the code is modified later on.
I replaced MIN with a simple if ... else structure so that I could test the code.

loop to reverse string in C

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.

How to replace the last index of a string using C language?

The code below tries to increment the last index in a string, eg: if label = "1_1_9", find_next_label (label ) will return "1_1_10".
This works. However, I also want to alter the original label, increment it as well. eg: if label = "1_1_9", find_next_label(label) will return "1_1_10" and during this procedure, label also becomes "1_1_10".
This code below is unable to do this. The result from main() function shows that label is still "1_1_9".
Could anyone help find where the problem is?
char * find_next_lable(char * label)
{
int length = strlen(label);
char * last_index = label + length - 1;
int num = atoi(last_index);
num = num + 1;
char * next_lable = malloc(sizeof(label));
strncpy(next_label, label, length-1);
*(next_label + length - 1) = '\0';
sprintf(next_label, "%s%d", next_label, num);
label = next_label;
return label;
}
int main()
{
char * s = malloc(6);
strcpy(s, "1_1_9");
char * n = find_next_label(s);
printf("%s\n", s);
printf("%s\n", n);
return 0;
}
The last_index() and atoi() code block assumes that the final number is only one digit long; clearly this is not very general. You could search for the last underscore instead, and convert a number from the character following that. Use strrchr() to look for the last underscore.
Also you must think a lot about buffer sizes and overruns, you should probably make the function accept the available buffer size as an additional argument especially if you want to modify the input. If you want that, there's of course no point in allocating additional space either, just return the input.
If you don't need to create a new string you can just do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 20
int main()
{
char *s = malloc(MAX_LEN); /* You must have enough memory if the number of chars grows! */
char *n;
int i;
strcpy(s, "1_1_9");
printf("%s\n", s);
n = strrchr(s, '_'); /* find the last '_' */
n++; /* and move to the number */
i = atoi(n);
sprintf(n, "%d", i+1); /* write the new value instead of the old one */
printf("%s\n", s);
free(s);
return 0;
}
else you can have the function:
char * find_next_lable(char *label)
{
char *n, *next_lable = malloc(sizeof(MAX_LEN));
int i;
strcpy(next_lable, label);
n = strrchr(next_lable, '_');
n++;
i = atoi(n);
sprintf(n, "%d", i+1);
return next_lable;
}
The result from main() function shows that lable is still 1_1_9.
That's because you are not changing the dynamically allocated array pointed to by s in main. Instead, you allocate new memory in the function find_next_lable. Also,
sprintf(next_lable, "%s%d", next_lable, num);
won't work since %s conversion specifier means that sprintf will read from the buffer pointed to by next_lable till and including the terminating null byte.
You must allocate enough memory so as to contain the incremented integer part.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// make sure MAX is large enough to
// contain the modified string
#define MAX 20
void find_next_lable(char *label);
int main(void)
{
char *s = malloc(MAX);
strcpy(s, "1_1_90");
printf("%s\n", s);
find_next_lable(s);
printf("%s\n", s); // prints 1_1_91
free(s);
return 0;
}
void find_next_lable(char *label)
{
// strrchr returns a pointer to the last
// occurrence of the character _ in label
char *last_index = strrchr(label, '_');
if(last_index == NULL)
{
last_index = label;
}
else
{
last_index++;
}
int num = atoi(last_index);
num = num + 1;
sprintf(last_index, "%d", num);
}

String (array) capacity via pointer

I am tring to create a sub-routine that inserts a string into another string. I want to check that the host string is going to have enough capacity to hold all the characters and if not return an error integer. This requires using something like sizeof but that can be called using a pointer. My code is below and I would be very gateful for any help.
#include<stdio.h>
#include<conio.h>
//#include "string.h"
int string_into_string(char* host_string, char* guest_string, int insertion_point);
int main(void) {
char string_one[21] = "Hello mother"; //12 characters
char string_two[21] = "dearest "; //8 characters
int c;
c = string_into_string(string_one, string_two, 6);
printf("Sub-routine string_into_string returned %d and creates the string: %s\n", c, string_one);
getch();
return 0;
}
int string_into_string(char* host_string, char* guest_string, int insertion_point) {
int i, starting_length_of_host_string;
//check host_string is long enough
if(strlen(host_string) + strlen(guest_string) >= sizeof(host_string) + 1) {
//host_string is too short
sprintf(host_string, "String too short(%d)!", sizeof(host_string));
return -1;
}
starting_length_of_host_string = strlen(host_string);
for(i = starting_length_of_host_string; i >= insertion_point; i--) { //make room
host_string[i + strlen(guest_string)] = host_string[i];
}
//i++;
//host_string[i] = '\0';
for(i = 1; i <= strlen(guest_string); i++) { //insert
host_string[i + insertion_point - 1] = guest_string[i - 1];
}
i = strlen(guest_string) + starting_length_of_host_string;
host_string[i] = '\0';
return strlen(host_string);
}
C does not allow you to pass arrays as function arguments, so all arrays of type T[N] decay to pointers of type T*. You must pass the size information manually. However, you can use sizeof at the call site to determine the size of an array:
int string_into_string(char * dst, size_t dstlen, char const * src, size_t srclen, size_t offset, size_t len);
char string_one[21] = "Hello mother";
char string_two[21] = "dearest ";
string_into_string(string_one, sizeof string_one, // gives 21
string_two, strlen(string_two), // gives 8
6, strlen(string_two));
If you are creating dynamic arrays with malloc, you have to store the size information somewhere separately anyway, so this idiom will still fit.
(Beware that sizeof(T[N]) == N * sizeof(T), and I've used the fact that sizeof(char) == 1 to simplify the code.)
This code needs a whole lot more error handling but should do what you need without needing any obscure loops. To speed it up, you could also pass the size of the source string as parameter, so the function does not need to calculate it in runtime.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
signed int string_into_string (char* dest_buf,
int dest_size,
const char* source_str,
int insert_index)
{
int source_str_size;
char* dest_buf_backup;
if (insert_index >= dest_size) // sanity check of parameters
{
return -1;
}
// save data from the original buffer into temporary backup buffer
dest_buf_backup = malloc (dest_size - insert_index);
memcpy (dest_buf_backup,
&dest_buf[insert_index],
dest_size - insert_index);
source_str_size = strlen(source_str);
// copy new data into the destination buffer
strncpy (&dest_buf[insert_index],
source_str,
source_str_size);
// restore old data at the end
strcpy(&dest_buf[insert_index + source_str_size],
dest_buf_backup);
// delete temporary buffer
free(dest_buf_backup);
}
int main()
{
char string_one[21] = "Hello mother"; //12 characters
char string_two[21] = "dearest "; //8 characters
(void) string_into_string (string_one,
sizeof(string_one),
string_two,
6);
puts(string_one);
return 0;
}
I tried using a macro and changing string_into_string to include the requirement for a size argument, but I still strike out when I call the function from within another function. I tried using the following Macro:
#define STRING_INTO_STRING( a, b, c) (string_into_string2(a, sizeof(a), b, c))
The other function which causes failure is below. This fails because string has already become the pointer and therefore has size 4:
int string_replace(char* string, char* string_remove, char* string_add) {
int start_point;
int c;
start_point = string_find_and_remove(string, string_remove);
if(start_point < 0) {
printf("string not found: %s\n ABORTING!\n", string_remove);
while(1);
}
c = STRING_INTO_STRING(string, string_add, start_point);
return c;
}
Looks like this function will have to proceed at risk. looking at strcat it also proceeds at risk, in that it doesn't check that the string you are appending to is large enough to hold its intended contents (perhaps for the very same reason).
Thanks for everyone's help.

Reversing a string in C using pointers?

Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}

Resources