I cant solve chaning characters - c

Required use of the function that returns the length of the string.
Write a function that receives two character chains (n1, n2). The function of the function is to check if the string n2 is the subscription of the string n1. The function returns the index of the first occurrence of the string n2 in the string n1 (if n2 is the string n1) or -1 (if n2 is not the string n1). assumption: the inscription n2 is shorter than the inscription n1.
Example: inscription n1: "Computer" inscription n2: "er" Function returns: 6
i did it and it work
#include <stdio.h>
#define LIMIT 50
char * string_in(char *string, char *substring);
char * get(char *string, int n);
int main(void)
{
// test string_in()
char string[LIMIT];
char substring[LIMIT];
char *substr_loc;
printf("Enter a string: ");
get(string, LIMIT);
while (string[0] != '\0')
{
printf("Enter a substring to look for: ");
get(substring, LIMIT);
substr_loc = string_in(string, substring);
if (substr_loc == NULL)
printf("%s not in %s\n", substring, string);
else
printf("%s found in %s at index %lu\n",
substring, string, substr_loc - string);
printf("Enter a string (empty line to quit): ");
get(string, LIMIT);
}
puts("Bye");
return 0;
}
char * string_in(char *string, char *substring)
{
// checks if substring is in string
// returns pointer to first location of substring
// in string or NULL if substring not in string
int i;
while (*string != '\0')
{
i = 0;
// check for substring at current location
while (*(string + i) == *(substring + i))
{
i++;
// if next char in substring is null, then match
// is found. return current location
if (*(substring + i) == '\0')
return string;
}
string++;
}
// no match
return NULL;
}
char * get(char *string, int n)
{
// wrapper for fgets that replaces first newline with null
char *return_value = fgets(string, n, stdin);
while (*string != '\0')
{
if (*string == '\n')
{
*string = '\0';
break;
}
string++;
}
return return_value;
}
the next step is
Write a part of the program that will replace all occurrences of the n2 string in the string n1 with the string (the character '*'). Use the function from a task point. Please tell me how to write this function
Example: n1: "Spectacle" n2: "c" string n1 after change. "Spe*ta*le"
void function(char * get, char * string_in)
int i = 0;
for ( i = 0; get[i]=!'\0';i++){
if (get[i] == string_in[o]
get[i] = '*';}
dont work;<

it is a bit more complicated if you the string which replaces another string is longer. Here you have simple functions.
size_t strstrIndex(const char *heap, const char *needle) // returns SIZE_MAX if not found
{
char *result = strstr(heap,needle);
return result ? result - heap : SIZE_MAX;
}
char *replace(const char *heap, const char *needle, const char *rep)
{
size_t pos = 0, nocc = 0;
size_t len = strlen(heap), nlen = strlen(needle), rlen = strlen(rep);
char *string;
char *wstr = (char *)heap;
while((pos = strstrIndex(wstr, needle)) != SIZE_MAX)
{
nocc++;
wstr += pos + nlen;
}
string = calloc(1, len + ((rlen > nlen) ? (rlen - nlen) * nocc : 0) + 1);
if(string)
{
wstr = string;
while((pos = strstrIndex(heap, needle)) != SIZE_MAX)
{
strncpy(wstr, heap, pos);
heap += pos + nlen;
wstr += pos;
strcpy(wstr, rep);
wstr += rlen;
}
if(*heap)
{
strcpy(wstr, heap);
}
}
return string;
}
int main()
{
char *heap = "Spectaclec";
printf("%s\n", replace(heap, "c", "*"));
printf("%s\n", replace(heap, "c", "*****"));
printf("%s\n", replace("ccSpecctaccleccX", "cc", "*****"));
}

This task is easy if you use the functions that comes with the C library:
void ReplaceString(char *pTarget, const char *pPattern)
{
char *p;
size_t PatternLength = strlen(pPattern);
// for all occurances of the pattern..
while (p = strstr(pTarget, pPattern))
{
// The function strstr found an occurance of the pattern.
// So it must be sufficient space in the target starting at the pointer p..
// replace the characters in the target
memset(p, '*', PatternLength);
}
}
If you should avoid functions for some academic purposes, you can implement your own versions of strlen, strstr, and memset. Your example shows a function string_in that looks like such version of `strstr.

Related

How to replace a part of a string with another substring

I need the string "on" to be replaced with "in", strstr() function returns a pointer to a string so i figured assigning the new value to that pointer would work but it didn't
#include <stdio.h>
#include <string.h>
int main(void) {
char *m = "cat on couch";
*strstr(m, "on") = "in";
printf("%s\n", m);
}
Replacing a substring with another is easy if both substrings have the same length:
locate the position of the substring with strstr
if it is present, use memcpy to overwrite it with the new substring.
assigning the pointer with *strstr(m, "on") = "in"; is incorrect and should generate a compiler warning. You would avoid such mistakes with gcc -Wall -Werror.
note however that you cannot modify a string literal, you need to define an initialized array of char so you can modify it.
Here is a corrected version:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[] = "cat on couch";
char *p = strstr(m, "on");
if (p != NULL) {
memcpy(p, "in", 2);
}
printf("%s\n", m);
return 0;
}
If the replacement is shorter, the code is a little more complicated:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[] = "cat is out roaming";
char *p = strstr(m, "out");
if (p != NULL) {
memcpy(p, "in", 2);
memmove(p + 2, p + 3, strlen(p + 3) + 1);
}
printf("%s\n", m);
return 0;
}
In the generic case, it is even more complicated and the array must be large enough to accommodate for the length difference:
#include <stdio.h>
#include <string.h>
int main(void) {
char m[30] = "cat is inside the barn";
char *p = strstr(m, "inside");
if (p != NULL) {
memmove(p + 7, p + 6, strlen(p + 6) + 1);
memcpy(p, "outside", 7);
}
printf("%s\n", m);
return 0;
}
Here is a generic function that handles all cases:
#include <stdio.h>
#include <string.h>
char *strreplace(char *s, const char *s1, const char *s2) {
char *p = strstr(s, s1);
if (p != NULL) {
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
if (len1 != len2)
memmove(p + len2, p + len1, strlen(p + len1) + 1);
memcpy(p, s2, len2);
}
return s;
}
int main(void) {
char m[30] = "cat is inside the barn";
printf("%s\n", m);
printf("%s\n", strreplace(m, "inside", "in"));
printf("%s\n", strreplace(m, "in", "on"));
printf("%s\n", strreplace(m, "on", "outside"));
return 0;
}
There are a few problems with this approach. First, off, m is pointing to read-only memory, so attempting to overwrite the memory there it is undefined behavior.
Second, the line: strstr(m, "on") = "in" is not going to change the pointed-to string, but instead reassign the pointer.
Solution:
#include <stdio.h>
#include <string.h>
int main(void)
{
char m[] = "cat on couch";
memcpy(strstr(m, "on"), "in", 2);
printf("%s\n", m);
}
Note that if you had just used plain strcpy it would null-terminate after "cat in", so memcpy is necessary here. strncpy will also work, but you should read this discussion before using it.
It should also be known that if you are dealing with strings that are not hard-coded constants in your program, you should always check the return value of strstr, strchr, and related functions for NULL.
This function performs a generic pattern replace for all instances of a substring with a replacement string. It allocates a buffer of the correct size for the result. Behaviour is well defined for the case of the empty substring corresponding to the javascript replace() semantics. Where possible memcpy is used in place of strcpy.
/*
* strsub : substring and replace substring in strings.
*
* Function to replace a substring with a replacement string. Returns a
* buffer of the correct size containing the input string with all instances
* of the substring replaced by the replacement string.
*
* If the substring is empty the replace string is written before each character
* and at the end of the string.
*
* Returns NULL on error after setting the error number.
*
*/
char * strsub (char *input, char *substring, char *replace)
{
int number_of_matches = 0;
size_t substring_size = strlen(substring), replace_size = strlen(replace), buffer_size;
char *buffer, *bp, *ip;
/*
* Count the number of non overlapping substring occurences in the input string. This
* information is used to calculate the correct buffer size.
*/
if (substring_size)
{
ip = strstr(input, substring);
while (ip != NULL)
{
number_of_matches++;
ip = strstr(ip+substring_size, substring);
}
}
else
number_of_matches = strlen (input) + 1;
/*
* Allocate a buffer of the correct size for the output.
*/
buffer_size = strlen(input) + number_of_matches*(replace_size - substring_size) + 1;
if ((buffer = ((char *) malloc(buffer_size))) == NULL)
{
errno=ENOMEM;
return NULL;
}
/*
* Rescan the string replacing each occurence of a match with the replacement string.
* Take care to copy buffer content between matches or in the case of an empty find
* string one character.
*/
bp = buffer;
ip = strstr(input, substring);
while ((ip != NULL) && (*input != '\0'))
{
if (ip == input)
{
memcpy (bp, replace, replace_size+1);
bp += replace_size;
if (substring_size)
input += substring_size;
else
*(bp++) = *(input++);
ip = strstr(input, substring);
}
else
while (input != ip)
*(bp++) = *(input++);
}
/*
* Write any remaining suffix to the buffer, or in the case of an empty find string
* append the replacement pattern.
*/
if (substring_size)
strcpy (bp, input);
else
memcpy (bp, replace, replace_size+1);
return buffer;
}
For testing purposes I include a main program that uses the replacement function.
#define BUFSIZE 1024
char * read_string (const char * prompt)
{
char *buf, *bp;
if ((buf=(char *)malloc(BUFSIZE))==NULL)
{
error (0, ENOMEM, "Memory allocation failure in read_string");
return NULL;
}
else
bp=buf;
printf ("%s\n> ", prompt);
while ((*bp=getchar()) != '\n')bp++;
*bp = '\0';
return buf;
}
int main ()
{
char * input_string = read_string ("Please enter the input string");
char * pattern_string = read_string ("Please enter the test string");
char * replace_string = read_string ("Please enter the replacement string");
char * output_string = strsub (input_string, pattern_string, replace_string);
printf ("Result :\n> %s\n", output_string);
free (input_string);
free (pattern_string);
free (replace_string);
free (output_string);
exit(0);
}

Need help to split a string by delimiter (and keep the delimiter in the token list)

I want to split a string by a delimiter and keep the delimiter in the token list
I have a function that do the same thing as strtok but with a string delimiter (instead of a set of chars) but it doesn't keep the delimiter and can't take an array of delimiters as argument
This is a function that split a string into tokens as strtok does but taking a delimiter
static char *strtokstr(char *str, char *delimiter)
{
static char *string;
char *end;
char *ret;
if (str != NULL)
string = str;
if (string == NULL)
return string;
end = strstr(string, delimiter);
if (end == NULL) {
char *ret = string;
string = NULL;
return ret;
}
ret = string;
*end = '\0';
string = end + strlen(delimiter);
return ret;
}
I want to have a char **split(char *str, char **delimiters_list) that split a string by a set of delimiters and keep the delimiter in the token list
I think I also need a function to count the number of tokens so i can malloc the return of my split function
// delimiters is an array containing ["&&", "||" and NULL]
split("ls > file&&foo || bar", delimiters) should return an array containing ["ls > file", "&&", "foo ", "||", " bar"]
How that can be achieved ?
First, you have a memory error here :
static char *string;
if (str != NULL)
string = str;
if (string == NULL)
return string;
If stris NULL, string is not initialised and you use a uninitialised value in comparaison.
if you want copy a string, you must use the strdup function, the = will just copy the pointer and not the pointer content.
And here a way to do it :
#include <stdlib.h>
#include <string.h>
char *get_delimiters(char *str, char **delims)
{
for (int i = 0; delims[i]; i++)
if (!strncmp(str, delims[i], strlen(delims[i])))
return delims[i];
return NULL;
}
char **split(char *str, char **delimiters)
{
char *string = strdup(str);
char **result = NULL;
int n = 0;
char *delim = NULL;
for (int i = 0; string[i]; i++)
if (get_delimiters(string + i, delimiters))
n++;
result = malloc((n * 2 + 2) * sizeof(char *));
if (!result)
return NULL;
result[0] = string;
n = 1;
for (int i = 0; string[i]; i++) {
delim = get_delimiters(string + i, delimiters);
if (delim) {
string[i] = '\0';
result[n++] = delim;
result[n++] = string + i + strlen(delim);
}
}
result[n] = NULL;
return result;
}
result :
[0] 'ls > file'
[1] '&&'
[2] 'foo '
[3] '||'
[4] ' bar'
remember result and string are malloced, so you must free the result and result[0]
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char **split(char *str, char **delimiters, int number_of_delimiters, int *number_of_rows_in_return_array);
int main()
{
char **split_str;
char *delimiters[] = {
"&&",
"||"
};
int rows_in_returned_array;
split_str = split("ls > file&&foo || bar && abc ||pqwe", delimiters, 2 , &rows_in_returned_array);
int i;
for (i = 0 ; i < rows_in_returned_array ; ++i)
{
printf("\n%s\n", split_str[i]);
}
return 0;
}
char **split(char *str, char **delimiters, int number_of_delimiters, int *number_of_rows_in_return_array)
{
//temporary storage for array to be returned
char temp_store[100][200];
int row = 0;//row size of array that will be returned
char **split_str;
int i, j, k, l, mark = 0;
char temp[100];
for (i = 0 ; str[i] != '\0' ; ++i)
{
//Iterating through all delimiters to check if any is str
for (j = 0 ; j < number_of_delimiters ; ++j )
{
l = i;
for (k = 0 ; delimiters[j][k] != '\0' ; ++k)
{
if (str[i] != delimiters[j][k])
{
break;
}
++l;
}
//This means delimiter is in string
if (delimiters[j][k] == '\0')
{
//store the string before delimiter
strcpy(temp_store[row], &str[mark]);
temp_store[row ++][i - mark] = '\0';
//store string after delimiter
strcpy(temp_store[row], &str[i]);
temp_store[row ++][k] = '\0';
//mark index where this delimiter ended
mark = l;
//Set i to where delimiter ends and break so that outermost loop
//can iterate from where delimiter ends
i = l - 1;
break;
}
}
}
//store the string remaining
strcpy(temp_store[row++], &str[mark]);
//Allocate the split_str and store temp_store into it
split_str = (char **)malloc(row * sizeof(char *));
for (i=0 ; i < row; i++)
{
split_str[i] = (char *)malloc(200 * sizeof(char));
strcpy(split_str[i], temp_store[i]);
}
*number_of_rows_in_return_array = row;
return split_str;
}
This should probably work. Note that I have passed int * number_of_rows_in_return_array by ref because we need to know the row size of the retuned array.
I went into abstraction. First I created a "sentence" library, that allows for manipulating NULL terminated list of strings (char*). I wrote some initial accessors (sentence_init, sentence_size, sentence_free, sentence_add_str etc.).
Then I went to split, witch becomes really, really easy then - if a delimeter is found, add the string up the delimeter to the sentence and add the delimeter to the sentence. Then increment the string pointer position. If the delimeter is not found, add the remaining string to the sentence.
There is a real problem with double pointers tho, because char ** is not implicitly convertible to const char **. For production code, I would probably aim to refactor the code, and try to take const-correctness into account.
#define _GNU_SOURCE 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <stdbool.h>
/*
* sentence - list of words
*/
/* ----------------------------------------------------------- */
// if this would be production code, I think I would go with a
// struct word_t { char *word; }; struct sentence_t { struct word_t *words; };
// Note: when sentence_add_* fail - they free *EVERYTHING*, so it doesn't work like realloc
// shared_ptr? Never heard of it.
char **sentence_init(void) {
return NULL;
}
size_t sentence_size(char * const *t) {
if (t == NULL) return 0;
size_t i;
for (i = 0; t[i] != NULL; ++i) {
continue;
}
return i;
}
void sentence_free(char * const *t) {
if (t == NULL) return;
for (char * const *i = t; *i != NULL; ++i) {
free(*i);
}
free((void*)t);
}
void sentence_printex(char * const *t, const char *fmt1, const char *delim, const char *end) {
for (char * const *i = t; *i != NULL; ++i) {
printf(fmt1, *i);
if (*(i + 1) != NULL) {
printf(delim);
}
}
printf(end);
}
void sentence_print(char * const *t) {
sentence_printex(t, "%s", " ", "\n");
}
void sentence_print_quote_words(char * const *t) {
sentence_printex(t, "'%s'", " ", "\n");
}
bool sentence_cmp_const(const char * const *t, const char * const *other) {
const char * const *t_i = t;
const char * const *o_i = other;
while (*t_i != NULL && o_i != NULL) {
if (strcmp(*t_i, *o_i) != 0) {
return false;
}
++t_i;
++o_i;
}
return *t_i == NULL && *o_i == NULL;
}
// thet's always funny, because "dupa" in my language means "as*"
char **sentence_add_strdupped(char **t, char *strdupped) {
const size_t n = sentence_size(t);
const size_t add = 1 + 1;
const size_t new_n = n + add;
void * const pnt = realloc(t, new_n * sizeof(char*));
if (pnt == NULL) goto REALLOC_FAIL;
// we have to have place for terminating NULL pointer
assert(new_n >= 2);
t = pnt;
t[new_n - 2] = strdupped;
t[new_n - 1] = NULL;
// ownership of str goes to t
return t;
// ownership of str stays in the caller
REALLOC_FAIL:
sentence_free(t);
return NULL;
}
char **sentence_add_strlened(char **t, const char *str, size_t len) {
char *strdupped = malloc(len + 1);
if (strdupped == NULL) goto MALLOC_FAIL;
memcpy(strdupped, str, len);
strdupped[len] = '\0';
t = sentence_add_strdupped(t, strdupped);
if (t == NULL) goto SENTENCE_ADD_STRDUPPED_FAIL;
return t;
SENTENCE_ADD_STRDUPPED_FAIL:
free(strdupped);
MALLOC_FAIL:
sentence_free(t);
return NULL;
}
char **sentence_add_str(char **t, const char *str) {
const size_t str_len = strlen(str);
return sentence_add_strlened(t, str, str_len);
}
/* ----------------------------------------------------------- */
/**
* Puff. Run strstr for each of the elements inside NULL delimeters dellist.
* If any returns not NULL, return the pointer as returned by strstr
* And fill dellist_found with the pointer inside dellist (can be NULL).
* Finally! A 3 star award is mine!
*/
char *str_find_any_strings(const char *str,
const char * const *dellist,
const char * const * *dellist_found) {
assert(str != NULL);
assert(dellist != NULL);
for (const char * const *i = &dellist[0]; *i != NULL; ++i) {
const char *found = strstr(str, *i);
if (found != NULL) {
if (dellist_found != NULL) {
*dellist_found = i;
}
// __UNCONST(found)
return (char*)found;
}
}
return NULL;
}
/**
* Split the string str according to the list od delimeters dellist
* #param str
* #param dellist
* #return returns a dictionary
*/
char **split(const char *str, const char * const *dellist) {
assert(str != NULL);
assert(dellist != NULL);
char **sen = sentence_init();
while (*str != '\0') {
const char * const *del_pnt = NULL;
const char *found = str_find_any_strings(str, dellist, &del_pnt);
if (found == NULL) {
// we don't want an empty string to be the last...
if (*str != '\0') {
sen = sentence_add_str(sen, str);
if (sen == NULL) return NULL;
}
break;
}
// Puff, so a delimeter is found at &str[found - str]
const size_t idx = found - str;
sen = sentence_add_strlened(sen, str, idx);
if (sen == NULL) return NULL;
assert(del_pnt != NULL);
const char *del = *del_pnt;
assert(del != NULL);
assert(*del != '\0');
const size_t del_len = strlen(del);
sen = sentence_add_strlened(sen, del, del_len);
if (sen == NULL) return NULL;
str += idx + del_len;
}
return sen;
}
int main()
{
char **sentence = split("ls > file&&foo || bar", (const char*[]){"&&", "||", NULL});
assert(sentence != NULL);
sentence_print_quote_words(sentence);
printf("cmp = %d\n", sentence_cmp_const((void*)sentence, (const char*[]){"ls > file", "&&", "foo ", "||", " bar", NULL}));
sentence_free(sentence);
return 0;
}
The program will output:
'ls > file' '&&' 'foo ' '||' ' bar'
cmp = 1

Appending two strings

I'm trying to write code to append two strings without the function strcat, but it doesn't work. It only works when the inputs are a single char.
Here's the code:
#include <stdio.h>
#include <string.h>
/*
Return the result of appending the characters in s2 to s1.
Assumption: enough space has been allocated for s1 to store the extra
characters.
*/
char* append (char s1[], char s2[]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
return s1;
}
int main ( ) {
char str1[10];
char str2[10];
while (1) {
printf ("str1 = ");
if (!gets(str1)) {
return 0;
};
printf ("str2 = ");
if (!gets(str2)) {
return 0;
};
printf ("The result of appending str2 to str1 is %s.\n",
append (str1, str2));
}
return 0;
}
How can I fix it?
You have some errors in your code:
Do not use gets. This function is dangerous because it doesn't take the
size of the buffer into account. Use fgets instead.
Your append function does not write the '\0'-terminating byte. It should
be
char* append (char s1[], char s2[]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
s1[k+s1len] = 0; // writing the 0-terminating byte
return s1;
}
str1 may be to short for holding both strings. If str2 contains "Hello"
and str2 contains "World!", you are going to overflow the buffer. Make the
buffer larger.
If you writing your own strcat, I would pass the size of the destination
buffer as well, so that you don't overflow the buffers:
char *mystrcat(char *t1, const char *t2, size_t maxsize)
{
if(t1 == NULL || t2 == NULL)
return NULL;
size_t s1 = strlen(t1);
size_t s2 = strlen(t2);
size_t i;
for(i = 0; i < s2 && (s1 + i) < maxsize - 1 ; ++i)
t1[i + s1] = t2[i];
t1[i + s1] = 0; // terminating the
return t1;
}
int main(void)
{
char str1[30] = "Hello ";
char str2[30] = "World!";
printf("mystrcat(\"%s\", \"%s\") = %s\n", str1, str2,
mystrcat(str1, str2, sizeof str1));
char str3[100] = "This is a long sentence";
printf("mystrcat(\"%s\", \"%s\") = %s\n", str1, str3,
mystrcat(str1, str3, sizeof str1));
char line[100];
printf("Enter some text: ");
fflush(stdout);
fgets(line, sizeof line, stdin);
line[strcspn(line, "\n")] = 0; // removing possible newline
strcpy(str3, "User input was: ");
printf("mystrcat: %s\n", mystrcat(str3, line, sizeof str3));
return 0;
}
That would return
mystrcat("Hello World!", "World!") = Hello World!
mystrcat("Hello World!This is a long se", "This is a long sentence") = Hello World!This is a long se
Enter some text: ABC DEF user input is great
mystrcat: User input was: ABC DEF user input is great
Your resulting string is not properly terminated.
Strings in C are always terminated with a NUL (0) character.
gets is unsafe, use fgets instead.
Get in the habit to check buffer sizes.
To give you an idea, here a minimalistic implementation using fgets + buffer size checks:
#include <stdio.h> // fprintf, fgets
#include <string.h> // strlen
const char *concatenate(char *dst, size_t sz, const char *s1, const char *s2) {
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
// Check for overflow
if ((l1 + l2 + 1) > sz) {
return NULL;
}
// Copy first string
for (size_t i = 0; i < l1; ++i) {
dst[i] = s1[i];
}
// Copy second string
for (size_t i = 0; i < l2; ++i) {
dst[l1 + i] = s2[i];
}
// Add NUL terminator
dst[l1 + l2 + 1] = 0;
return dst;
}
int main() {
// Allocate two strings (9 chars max.)
char first_string[10];
char second_string[10];
char concatenated_string[20];
// Read first string from stdin
fprintf(stdout, "str1 = ");
// !!! fgets return value check omitted for simplicity.
fgets(first_string, sizeof(first_string), stdin);
// Read second string from stdin
fprintf(stdout, "str2 = ");
// !!! fgets return value check omitted for simplicity.
fgets(second_string, sizeof(second_string), stdin);
const char *tmp = concatenate(concatenated_string, sizeof(concatenated_string), first_string, second_string);
if (!tmp) {
fprintf(stderr, "would overflow\n");
} else {
fprintf(stdout, "concatenated: %s\n", concatenated_string);
}
return 0;
}

C trying to copy pointer to a new pointer

I need help with a couple of things:
I'm trying to delete a word from a pointer and put it in a new pointer with a new length but i am not able to copy it to the new pointer
I'm not sure when should I use the free() function.
when I use the free(str) in the delete function it crashes.
After I copy the "str" to the "newStr" what is the best way to copy the "newStr" back to the "str" with the new length?
Please help me understand it, I'm new with this and I googled it, I tried looking here and didn't find something that could help me.
void delete(char *str)
{
int i, indexStart = 0, indexEnd = 0, wordlen = 0, newLen = 0, len = 0;
printf("Enter the index of the word that you want to remove: ");
scanf("%d", &i);
indexs(i, str,&indexStart,&indexEnd,&wordlen);
len = strlen(str);
newLen = len - wordlen - 1;
char *newStr = (char*)malloc(newLen * sizeof(char));
if (newStr == NULL)
{
printf("Error! memory not allocated.");
exit(0);
}
for (int j = 0; j < len; j++)
{
if (j< (indexStart - 1) || j > indexEnd)
{
*newStr = *str;
newStr++;
}
str++;
}
free(str);
//free(newStr);
printf("The new string: %s\n", newStr);
}
void main()
{
char *str = (char*)malloc(1 * sizeof(char));
if (str == NULL)
{
printf("Error! memory not allocated.");
exit(0);
}
text(str);
if (str != NULL)
{
delete(str);
}
free(str);
system("pause");
}
According to the structured programming paradigm your functions should solve small separate tasks. But your function delete() prints to the console, scans input, allocates new string and fills this new string. But what's event worse is the call exit() in this function. If something went wrong, function must to return an error, but not to stop the program. Also names of functions should relfect what they do.
Use free() for every memory block allocated by malloc().
So, this is a working code:
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
const char *findWord(const char *str, const char *delimiters, unsigned index) {
// validate input parameters
if (!str || !delimiters) {
return NULL;
}
// count words
unsigned count = 0;
while (*str && count < index) {
// skip delimiters
while (*str && !strchr(delimiters, *str)) {
str++;
}
if (*str) {
count++;
}
// skip word
while (*str && strchr(delimiters, *str)) {
str++;
}
}
// if index is too big returns NULL
return *str ? str : NULL;
}
unsigned countLengthOfWord(const char *str, const char *delimiters) {
// validate input parameters
if (!str || !delimiters) {
return 0;
}
// count length
unsigned length = 0;
while (*str && !strchr(delimiters, *str++)) {
length++;
}
return length;
}
char *cutWord(char *str, const char *delimiters, unsigned index) {
// validate input parameters
if (!str) {
return NULL;
}
str = (char *)findWord(str, delimiters, index);
// if index is too big, return NULL
if (!str) {
return NULL;
}
// allocate new string for word
unsigned length = countLengthOfWord(str, delimiters);
char *word = malloc(length + 1);
// check if allocation was successfull
if (!word) {
return NULL;
}
// copy word
strncpy(word, str, length);
word[length] = '\0';
// cut word from string
const char *ptr = str + length;
while (*ptr) {
*str++ = *ptr++;
}
*str = '\0';
return word;
}
int main() {
char str1[] = "Hello, my world!";
char str2[] = "Hello, my world!";
char str3[] = "Hello, my world!";
char *word1 = cutWord(str1, " ,!", 0);
char *word2 = cutWord(str2, " ,!", 1);
char *word3 = cutWord(str3, " ,!", 2);
if (word1) {
printf("word: %s\nstring: %s\n\n", word1, str1);
}
if (word2) {
printf("word: %s\nstring: %s\n\n", word2, str2);
}
if (word3) {
printf("word: %s\nstring: %s\n\n", word3, str3);
}
// release allocated memory
free(word1);
free(word2);
free(word3);
getchar();
return 0;
}

String Split in C

I want to split a String in C.
My String is defined by my Struct:
struct String
{
char *c;
int length;
int maxLength;
}
Then I have a function that does the splitting. Perhaps C has something that does this, but although I wanted my own, I have not found anything that will do it so far.
String ** spliter(String *s)
{
if(s == NULL)
return NULL;
// set of splitters: {'\n', ' '}
}
Input looks something like this: This is Sparta.
Then I want to return a pointer to each character array.
*p1 = This
*p2 = is
*p3 = Sparta.
If that makes any sense, I want an array of pointers, and each pointer points to a character array.
I will have to realloc the String as I increment the size of each character array. Probably my biggest problem is imagining how the pointers work.
Similar problem: c splitting a char* into an char**
So, how do I go about doing this?
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string test = "aa aa bbc cccd";
vector<string> strvec;
string strtemp;
string::size_type pos1, pos2;
pos2 = test.find(' ');
pos1 = 0;
while (string::npos != pos2)
{
strvec.push_back(test.substr(pos1, pos2 - pos1));
pos1 = pos2 + 1;
pos2 = test.find(' ', pos1);
}
strvec.push_back(test.substr(pos1));
vector<string>::iterator iter1 = strvec.begin(), iter2 = strvec.end();
while (iter1 != iter2)
{
cout << *iter1 << endl;
++iter1;
}
return 0;
}
Have you looked at strtok? It should be possible to do this using strtok.
here is a exemple :
String ** spliter(String *s)
{
int i;
int j;
char *p1;
char *p2;
char *p3;
i = 0;
j = 0;
if(s == NULL)
return NULL;
p1 = malloc(sizeof(*p1) * strlen(s));
p2 = malloc(sizeof(*p2) * strlen(s));
p3 = malloc(sizeof(*p3) * strlen(s));
while (s[i] != ' ')
{
p1[j++] = s[i];
i++;
}
i++;
j = 0;
while (s[i] != ' ')
{
p2[j++] = s[i];
i++;
}
i++;
j = 0;
while (s[i] != '\0')
{
p3[j++] = s[i];
i++;
}
printf("%s\n", p1);
printf("%s\n", p2);
printf("%s\n", p3);
}
You're looking for strtok, check out man 3 strtok, or here if you're not on *nix.
You would use it like this: (Assuming that you can write the add_string code yourself.)
String ** spliter(String *s)
{
if(s == NULL)
return NULL;
String **return_strings = NULL;
char *delim = " \n";
char *string = strtok(s, delim);
int i = 0;
for(i = 0; add_string(return_strings, string, i) != -1; i++) {
string = strtok(NULL, delim);
}
return strings;
}
Note that if you need to save the original string (strtok modifies the string it works on), you'll need to call strdup on the original string, then operate on the copy.
EDIT: OP said he was having trouble thinking about the pointers. With the above code sample, add_string only has to worry about dealing with a string of characters, as opposed to an array of pointers to pointers to characters. So it might look something like this:
int add_string(String **strings, char *s, int len)
{
if(s == NULL)
return -1;
String *current_string = NULL;
strings = realloc(strings, sizeof(String) * (len + 1));
current_string = strings[len];
/* fill out struct fields here */
}
add strdup and strtok can work on a copy of the string. The split() call is more generic than the other spliter() examples, but does the same thing with strtok on a duplicate.
char **
split(char **result, char *w, const char *src, const char *delim)
{
int i=0;
char *p;
strcpy(w,src);
for(p=strtok(w, delim) ; p!=NULL; p=strtok('\0', delim) )
{
result[i++]=p;
result[i]=NULL;
}
return result;
}
void display(String *p)
{
char *result[24]={NULL};
char *w=strdup(p->c);
char **s=split(result, w, p->, "\t \n"); split on \n \t and space as delimiters
for( ; *s!=NULL; s++)
printf("%s\n", *s);
free(w);
}

Resources