#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char * str = "Testing replace text...\n\n";
char* buffer = malloc(sizeof(char));
char* insertPoint = &buffer[0];
char* copy = str;
char* p = strstr(str, "epl");
char* g = "gard";
int size = 0;
size = p-copy; //p = 9, which is the number of elemts till the first element of the substring
//want to allocate this space, and then increment insertPoint, by that amt(it'll be pointing
// to nothing)
buffer = realloc(buffer, size);
printf("Size: %d\n", size);
memcpy(insertPoint, copy, size);
printf("COPY: %s\n", buffer);
copy += size;
buffer = realloc(buffer, size+strlen(g));
insertPoint += size;
printf("%c", *insertPoint);
memcpy(insertPoint, g, strlen(g)); //insert after the 9 letters, the string the size of g
size += strlen(g); //size if the size of the buffer
printf("Size2: %d\n", size);
printf("COPY2: %s\n", buffer);
return EXIT_SUCCESS;
}
Just some quick experimental code; I am just trying to replace the substring epl in str with "gard" but when I print it out there are no changes to the string buffer I am printing, meaning the first string im printing works where it gets all the letters into buffer before the substring occurs, but when I try to replace with substring it doesn't work. I've testing the individual pointers and they all seem correct...not sure what is happening, any insight? Thanks...fully runnable program.
I think the problem in your code arise because strlen does not include the terminating zero. I tried to fix your code but in the end I found it easier to re-write it anew (and using more sensible variable names).
The following simple four steps work. The continuous use of strlen may be replaced by variables, but I left them for clarity. (Also, a good compiler may very well optimize this code by leaving the calls out.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *str = "Testing replace text...\n\n";
char* buffer;
char* find_str = "epl";
char* repl_str = "gard";
char *find_str_pos = strstr (str, find_str);
/* 1. create new buffer of the correct size */
buffer = malloc (strlen(str) - strlen(find_str) + strlen(repl_str) + 1);
/* 2. copy first part */
memcpy (buffer, str, find_str_pos - str);
/* 3. add new text */
memcpy (buffer + (find_str_pos - str), repl_str, strlen(repl_str));
/* 4. append original text */
memcpy (buffer + (find_str_pos - str) + strlen(repl_str), find_str_pos + strlen(find_str), strlen(find_str_pos) - strlen(repl_str) + 1);
printf ("-> [%s]\n", buffer);
return EXIT_SUCCESS;
}
You are not appending remaining text "ace text..." after replacing "epl".
Can you try code below
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
char *source_string = "Testing replace text...";
char *search_string = "epl";
char *replace_string = "gard";
int search_length = strlen(search_string);
int replace_length = strlen(replace_string);
// Find start position of search string
char *start = strstr(source_string, search_string); // start pointing to "eplace text..."
int intial_length = start - source_string; // intial_length = 9
// Get remaining text which should append after replace
char *remaining_string = (start + search_length); // remaining_string pointing to "ace text..."
int remaining_length = strlen(remaining_string); // remaining_length = 11
// Find total length of string after replacing text
int total_string_length = intial_length + replace_length + remaining_length; // 24
char *buffer = (char *)malloc(total_string_length + 1); // +1 for null pointer
char *current_index = buffer;
// Add initial text
memcpy(current_index, source_string, intial_length);
current_index += intial_length;
// Add replace text
memcpy(current_index, replace_string, replace_length);
current_index += replace_length;
// Add remaining text
memcpy(current_index, remaining_string, remaining_length);
current_index += remaining_length;
memcpy(current_index, "\0", 1); // add null pointer at last
printf("Final Output: %s", buffer); // Final Output: Testing rgardace text...
return 0;
}
Related
Making a function for adding a customer record on to a text file.
I have made a function that would trim leading and last spaces off customer name etc, called trimspaces.
the function addrecord is to handle storing of record in file. It gets given 3 parameters (name /address/ phone). Before storing operation function will remove whitespaces using trimspaces function, then combine the 3 strings to one.
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> //mkdir
#include <stdio.h> //printf
#include <errno.h> //error number
#include <unistd.h> //access
#include <string.h> //strcat
#include <ctype.h> //isspace
#include <stdlib.h>//malloc
int checkFile();
int makeFile();
int addRecord(char* name, char* addr, char* phon);
int searchRec(int column, char* value);
char* getRec(int recNo);
int getRecNo();
char* trimspaces(char* string,char*ptr);
int addRecord(char* name, char* addr, char* phon){
printf("\n- starting records addReord function -\n");
int success = 0;
char* namt = trimspaces(name,namt);
char* addt = trimspaces(addr,addt);
char* phot = trimspaces(phon,phot);
//this prints "trimmed words: , , "
printf("\n trimmed words: %s, %s, %s",namt,addt,phot);
/*
char*combined1 = strcat(namt,"|");
char*combined2 = strcat(combined1,addt);
char*combined3 = strcat(combined2,"|");
char*combined4 = strcat(combined3,phot);
printf("\nwords combined: %s",combined4);
*/
printf("\n- leaving records addrecord function -\n");
return success;
}
char* trimspaces(char* string,char*ptr){
printf("\n- entered trimspaces function -");
char *str= string;
int slen = strlen(str); //string length
int ctfor = 0; //counter forward
int ctbak = 0; //counter back
while(isspace(*str)){ str++; ctfor++; }; //count to start of word
while(*str){str++;}; //go to end
do{ str--; ctbak++; }while(isspace(*str)); //count from end to end of word
int cbako = (slen - ctbak) + 1; //counter back reversed
int wlen = cbako - ctfor; //get word length
printf("\nstr_len:%d,counter_fore:%d,counter_bak:%d,cbakreversed:%d,wlen:%d",slen,ctfor,ctbak,cbako,wlen);
while(*str){ str--; }
str++;
while(isspace(*str)){
str++;
}
char newStr[wlen]; //char pointer gives segmentation fault
memcpy(newStr,str,wlen);
printf("\n--%s--",newStr);
ptr = malloc(sizeof(newStr)+1);
ptr = newStr;
printf("\nPTR is : %s",ptr);
return ptr;
printf("\n- leaving trimspaces function -");
}
int main(){
addRecord("kara","19,sams st","993328");
}
THIS IS THE OUTPUT:
(I want the text between --text-- to be string with leading/end spaces remvoed, and timmed words lines to say - TRIMMED words: kara,19,sams st,993328)
- starting records addReord function -
- entered trimspaces function -
str_len:4,counter_fore:0,counter_bak:1,cbakreversed:4,wlen:4
--kara--
PTR is : kara
- entered trimspaces function -
str_len:10,counter_fore:0,counter_bak:1,cbakreversed:10,wlen:10
--19,sams st#--
PTR is : 19,sams st#
- entered trimspaces function -
str_len:6,counter_fore:0,counter_bak:1,cbakreversed:6,wlen:6
#--93328s W
#TR is : 993328s W
TRIMMED words: , ,
- leaving records addrecord function -
Ive met 2 problems in the output of main function. first the printed string at - printf("\n TRIMMED words: %s, %s, %s",namt,addt,phot);
reads : TRIMMED words: , ,
Ive tried a number of things but the returned variables are always blank. I wonder if Im using malloc and pointers right.
second problem is
--19,sams st#--
PTR is : 19,sams st#
#--93328s W
#TR is : 993328s W
I dont know where the # and Ws come from. When I tested trimspaces function with different values it printed correct results.
I will note here that I used export PS1='\u#\h: ' on terminal for a shorter prompt.
what should I do to get the variables to print values?
Based on the feedback given Ive modified the code to correct some of the mistakes. this code may not be quite proper and there are still problems(apparently blank inputs strings to trimspaces function gives errors - Im leaving this problem alone and moving on for the moment)
after some digging I found that you need to pass a pointer to a pointer (**) for malloc to work on the variable passed to a different function. still dont understand these principles well but it seems to work. also use strcat on pointer space and char array instead of use of direct = operator.
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> //mkdir
#include <stdio.h> //printf
#include <errno.h> //error number
#include <unistd.h> //access
#include <string.h> //strcat
#include <ctype.h> //isspace
#include <stdlib.h>//malloc
int addRecord(char* name, char* addr, char* phon);
void trimspaces(char* string,char**ptr);
int addRecord(char* name, char* addr, char* phon){
printf("\n- starting records addReord function -\n");
int success = 0;
char* namt = "";
trimspaces(name,&namt);
char* addt = "";
trimspaces(addr,&addt);
char* phot = "";
trimspaces(phon,&phot);
//this prints "trimmed words: , , "
printf("\n TRIMMED words: %s, %s, %s",namt,addt,phot);
printf("\n- leaving records addrecord function -\n");
return success;
}
void trimspaces(char* string, char** ptr){
printf("\n- entered trimspaces function -");
//PROBLEMS WITH 0 SIZE OR BLANK INPUT
char *str= string;
int slen = strlen(str); //string length
int ctfor = 0; //counter forward
int ctbak = 0; //counter back
while(isspace((unsigned char)*str)){ str++; ctfor++; }; //count to start of word
while(*str){str++;}; //go to end
//unsigned char
do{ str--; ctbak++; }while(isspace((unsigned char)*str)); //count from end to end of word
int cbako = (slen - ctbak) + 1; //counter back reversed
int wlen = cbako - ctfor; //get word length
printf("\nstr_len:%d,counter_fore:%d,counter_bak:%d,cbakreversed:%d,wlen:%d",slen,ctfor,ctbak,cbako,wlen);
while(*str){ str--; }
str++;
while(isspace((unsigned char)*str)){
str++;
}
char newStr[wlen+1]; //char pointer gives segmentation fault
memcpy(newStr,str,wlen); //not null terminated
newStr[wlen] = '\0';
printf("\n--%s--",newStr);
//PASS POINTER TO POINTER for malloc to work / malloc inside another function
*ptr = malloc(sizeof(newStr)+1); //memory
strcat(*ptr,newStr);
printf("\nPTR is : %s",*ptr);
printf("\n- leaving trimspaces function -");
}
int main(){
addRecord(" ertsfs "," 120,Dans st "," 111 000 222");
}
No need to pass ptr as argument to trimspaces calls.
This works (even if string is just whitespaces or empty):
char *trimspaces(char *string){
size_t len = strlen(string);
char *s = string; //start
char *e = string + len - 1; //end
while(s <= e && isspace(*s)) s++;
while(e >= s && isspace(*e)) e--;
size_t size = e - s + 1;
char *ptr = (char*) malloc(size + 1);
int i;
for(i = 0; i < size; i++)
ptr[i] = s[i];
ptr[i] = '\0';
return ptr;
}
If you encounter any problem with pointers out-of-bound (which I doubt) try this using indexes instead of pointers:
char *trimspaces(char *string){
int len = strlen(string);
int s = 0; //start
int e = len - 1; //end
while(s <= e && isspace(string[s])) s++;
while(e >= s && isspace(string[e])) e--;
int size = e - s + 1;
char *ptr = (char *) malloc(size + 1);
int i;
for(i = 0; i < size; i++)
ptr[i] = string[i + s];
ptr[i] = '\0';
return ptr;
}
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.
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);
}
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.
I have char * source, and I want extract from it subsrting, that I know is beginning from symbols "abc", and ends where source ends. With strstr I can get the poiner, but not the position, and without position I don't know the length of the substring. How can I get the index of the substring in pure C?
Use pointer subtraction.
char *str = "sdfadabcGGGGGGGGG";
char *result = strstr(str, "abc");
int position = result - str;
int substringLength = strlen(str) - position;
newptr - source will give you the offset.
char *source = "XXXXabcYYYY";
char *dest = strstr(source, "abc");
int pos;
pos = dest - source;
Here is a C version of the strpos function with an offset feature...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strpos(char *haystack, char *needle, int offset);
int main()
{
char *p = "Hello there all y'al, hope that you are all well";
int pos = strpos(p, "all", 0);
printf("First all at : %d\n", pos);
pos = strpos(p, "all", 10);
printf("Second all at : %d\n", pos);
}
int strpos(char *hay, char *needle, int offset)
{
char haystack[strlen(hay)];
strncpy(haystack, hay+offset, strlen(hay)-offset);
char *p = strstr(haystack, needle);
if (p)
return p - haystack+offset;
return -1;
}
If you have the pointer to the first char of the substring, and the substring ends at the end of the source string, then:
strlen(substring) will give you its length.
substring - source will give you the start index.
Formally the others are right - substring - source is indeed the start index. But you won't need it: you would use it as index into source. So the compiler calculates source + (substring - source) as the new address - but just substring would be enough for nearly all use cases.
Just a hint for optimization and simplification.
A function to cut a word out out of a string by a start and end word
string search_string = "check_this_test"; // The string you want to get the substring
string from_string = "check"; // The word/string you want to start
string to_string = "test"; // The word/string you want to stop
string result = search_string; // Sets the result to the search_string (if from and to word not in search_string)
int from_match = search_string.IndexOf(from_string) + from_string.Length; // Get position of start word
int to_match = search_string.IndexOf(to_string); // Get position of stop word
if (from_match > -1 && to_match > -1) // Check if start and stop word in search_string
{
result = search_string.Substring(from_match, to_match - from_match); // Cuts the word between out of the serach_string
}