I call below function which is written in C to fetch parent of child-
char *getParent(char *child)
{
int len = strlen(child);
char *parent;
parent = strdup(substring(child, 0, len - 4));
return parent;
}
char *substring(const char* str, int beg, int n)
{
char *ret = malloc(n+1);
strncpy(ret, (str + beg), n);
*(ret+n) = '\n';
return strdup(ret);
}
child is - '11112222'
Now I am expecting output - '1111' but this function also adding extra spaces after 1111 like this '1111---here i am getting space----'.
What's wrong in this function ?
This:
*(ret+n) = '\n';
is wrong, it should be:
*(ret+n) = '\0';
to terminate the string. You're adding a linefeed, not a terminator, thus failing to produce a valid string.
Also, I would recommend prefering indexing since it's a bit cleaner syntactically:
ret[n] = '\0';
And, of course, you should check the return value of malloc() before relying on it.
UPDATE: And gosh, remove that strdup(), it's completely pointless now that you've already malloc()ed your new string.
It should be just:
char * substring(const char *str, size_t beg, size_t n)
{
char *ret = malloc(n + 1);
if(ret != NULL)
{
strncpy(ret, str + beg, n);
ret[n] = '\0';
}
return ret;
}
This still assumes that the offset and length are valid, and that str is non-NULL.
Related
I am using the below function to replace a sub-string in a given string
void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *result = NULL;
int i, cnt = 0;
int tolen = strlen(to);
int fromlen = strlen(from);
if (*inputString == NULL)
return;
// Counting the number of times old word
// occur in the string
for (i = 0; (*inputString)[i] != '\0'; i++)
{
if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
{
cnt++;
// Jumping to index after the old word.
i += fromlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return;
memset(result, 0, i + cnt * (tolen - fromlen) + 1);
i = 0;
while (&(*inputString))
{
// compare the substring with the result
if (strstr(*inputString, from) == *inputString)
{
strncpy(&result[i], to, strlen(to));
i += tolen;
*inputString += fromlen;
}
else
{
result[i++] = (*inputString)[0];
if ((*inputString)[1] == '\0')
break;
*inputString += 1;
}
}
result[i] = '\0';
*inputString = result;
return;
}
The problem with the above function is memory leak. Whatever memory is allocated for inputString will be lost after this line.
*inputString = result;
since I am using strstr and moving pointer of inputString *inputString += fromlen; inputString is pointing to NULL before the above line. So how to handle memory leak here.
Note: I dont want to return the new memory allocated inside the function. I need to alter the inputString memory based on new length.
You should use a local variable to iterate over the input string and avoid modifying *inputString before the final step where you free the previous string and replace it with the newly allocated pointer.
With the current API, ReplaceSubStr must be called with the address of a pointer to a block allocated with malloc() or similar. Passing a pointer to local storage or a string literal will have undefined behavior.
Here are a few ideas for improvement:
you could return the new string and leave it to the caller to free the previous one. In this case, you would take the input string by value instead of by address:
char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
If the from string is empty, you should either insert the to string between each character of the input string or do nothing. As posted, your code has undefined behavior for this border case.
To check if the from string is present at offset i, use memcmp instead of strstr.
If cnt is 0, there is nothing to do.
You should return an error status for the caller to determine if memory could be allocated or not.
There is no need to initialize the result array.
avoid using strncpy(). This function has counter-intuitive semantics and is very often misused. Read this: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ReplaceSubStr(char **inputString, const char *from, const char *to) {
char *input = *inputString;
char *p, *q, *result;
size_t cnt;
size_t tolen = strlen(to);
size_t fromlen = strlen(from);
if (input == NULL || fromlen == 0)
return 0;
// Counting the number of times old word occurs in the string
for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
p += fromlen;
}
if (cnt == 0) // no occurrence, nothing to do.
return 0;
// Making new string of enough length
result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return -1;
for (p = input, q = result;;) {
char *p0 = p;
p = strstr(p, from);
if (p == NULL) {
strcpy(q, p0);
break;
}
memcpy(q, p0, p - p0);
q += p - p0;
memcpy(q, to, tolen);
q += tolen;
p += fromlen;
}
free(*inputString);
*inputString = result;
return 0;
}
int main() {
char *p = strdup("Hello world!");
ReplaceSubStr(&p, "l", "");
printf("%s\n", p); // prints Heo word!
free(p);
return 0;
}
You cannot obviously free the input as it can be a literal, some memory you don't control. That would cripple your function even more than now.
You could return the old value of inputString so you'd be able to free it if needed.
char *ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *old_string = *inputString;
...
return old_string;
}
The caller is responsible to free the contents of old_string if needed.
If not needed (we have to workaround the char ** input by assigning a valid writable array to a pointer to be able to pass this pointer:
char input[]="hello world";
char *ptr = input;
ReplaceSubStr(&ptr, "hello", "hi");
// input is now "hi world" in a different location
free(ptr); // when replaced string isn't needed
if needed:
char *input = strdup("hello world");
char *old_input = ReplaceSubStr(&input, "hello", "hi");
free(old_input);
or just
free(ReplaceSubStr(&input, "hello", "hi"));
then always (when replaced string isn't needed):
free(input);
The only constraint is that you cannot use a constant string literal as input (const char *input = "hello world") because of the prototype & the possible return of a char * to pass to free.
I'm a bit of a newbie at C, so please bear with me...
I have a function to count char in a string called char strLength, but I have to create a function that uses this function to count the number of characters in a passed string, mallocates a new string with space for a NULL terminator, copies the string and then returns the copy.
Here's what I have:
character counter
int strLength(char* toCount)
{
int count = 0;
while(*toCount != '\0')
{
count++;
toCount++;
}
return count;
}
and here's the beginning of the sought-after function
char* strCopy(char *s)
{
int length = strLength(s);
}
Since you are struggling with malloc, here is how the next line should look:
char* strCopy(char *s)
{
int length = strLength(s);
char *res = malloc(length+1);
// Copy s into res; stop when you reach '\0'
...
return res;
}
You want strdup. However, since I suspect this is a learning exercise:
char *strCopy(const char *src)
{
size_t l = strlen(src) + 1;
char *r = malloc(l);
if (r)
memcpy(r, src, l);
return r;
}
If you are curious how to copy strings yourself, you could replace the memcpy with something like:
char *dst = r;
while (*src)
*dst++ = *src++;
*dst = 0;
However I would suggest using library functions: if not strdup, then malloc + memcpy.
You can use strdup() clib call.
You can write something like:
char* strCopy(char *s) {
int length = strLength(s);
char *rc = (char *)malloc(length + 1);
return rc? strcpy(rc, s) : NULL;
}
Folks, need to search through a character array and replace any occurrence of '+','/',or'=' with '%2B','%2F', and '%2F' respectively
base64output variable looks like
FtCPpza+Z0FASDFvfgtoCZg5zRI=
code
char *signature = replace_char(base64output, "+", "%2B");
signature = replace_char(signature, "/", "%2F");
signature = replace_char(signature, "=", "%3B");
char replace_char (char *s, char find, char replace) {
while (*s != 0) {
if (*s == find)
*s = replace;
s++;
}
return s;
}
(Errors out with)
s.c:266: warning: initialization makes pointer from integer without a cast
What am i doing wrong? Thanks!
If the issue is that you have garbage in your signature variable:
void replace_char(...) is incompatible with signature = replace_char(...)
Edit:
Oh I didn't see... This is not going to work since you're trying to replace a char by an array of chars with no memory allocation whatsoever.
You need to allocate a new memory chunk (malloc) big enough to hold the new string, then copy the source 's' to the destination, replacing 'c' by 'replace' when needed.
The prototype should be:
char *replace_char(char *s, char c, char *replace);
1.
for char use '' single quotes
for char* use "" double quotes
2.
The function does include the return keyword, therefore it does not return what you'd expect
3.
These webpages have examples on string replacement
http://www.cplusplus.com/reference/cstring/strstr/
What is the function to replace string in C?
You could go for some length discussing various ways to do this.
Replacing a single char is simple - loop through, if match, replace old with new, etc.
The problem here is that the length of the "new" part is longer than the length of the old one.
One way would be to determine the length of the new string (by counting chars), and either (1) try to do it in place, or (2) allocate a new string.
Here's an idea for #1:
int replace(char *buffer, size_t size, char old, const char *newstring)
{
size_t newlen = strlen(newstring);
char *p, *q;
size_t targetlen = 0;
// First get the final length
//
p = buffer;
while (*p)
{
if (*p == old)
targetlen += newlen;
else
targetlen++;
++p;
}
// Account for null terminator
//
targetlen++;
// Make sure there's enough space
//
if (targetlen > size)
return -1;
// Now we copy characters. We'll start at the end and
// work our way backwards.
//
p = buffer + strlen(buffer);
q = buffer + targetlen;
while (targetlen)
{
if (*p == old)
{
q -= newlen;
memcpy(q, newstring, newlen);
targetlen -= newlen;
--p;
}
else
{
*--q = *p--;
--targetlen;
}
}
return 0;
}
Then you could use it this way (here's a quick test I did):
char buf[4096] = "hello world";
if (replace(buf, sizeof(buf), 'o', "oooo"))
{
fprintf(stderr, "Not enough space\n");
}
else
{
puts(buf);
}
your replace_char signature returns void
void replace_char (char *s, char find, char replace)
But, when the linker tries to resolve the following
signature = replace_char(signature, "=", '%3B');
It doesn't find any function that's called replace_char and returns int (int is the default if there's no prototype).
Change the replace_char function prototype to match the statement.
EDIT:
The warning states that your function returns char, but you use it as a char *
also, your function doesn't return anything, do you need to return something ?
It looks like you don't really understand the code that you're working with.
Fixing errors and warnings without understanding exactly what you need to do is worthless..
fix like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_char (char *str, char find, char *replace) {
char *ret=str;
char *wk, *s;
wk = s = strdup(str);
while (*s != 0) {
if (*s == find){
while(*replace)
*str++ = *replace++;
++s;
} else
*str++ = *s++;
}
*str = '\0';
free(wk);
return ret;
}
int main(void){
char base64output[4096] = "FtCPpza+Z0FASDFvfgtoCZg5zRI=";
char *signature = replace_char(base64output, '+', "%2B");
signature = replace_char(signature, '/', "%2F");
signature = replace_char(signature, '=', "%3B");
printf("%s\n", base64output);
return 0;
}
below is a code that ACTUALLY WORKS !!!!
Ammar Hourani
char * replace_char(char * input, char find, char replace)
{
char * output = (char*)malloc(strlen(input));
for (int i = 0; i < strlen(input); i++)
{
if (input[i] == find) output[i] = replace;
else output[i] = input[i];
}
output[strlen(input)] = '\0';
return output;
}
I'm sorry if this is too entry-level, but I tried implementing the library function of strcpystrncat() as follows:
#include <stdio.h>
void strncat (char *s, char *t, int n) {
// malloc to extend size of s
s = (char*)malloc (strlen(t) + 1);
// add t to the end of s for at most n characters
while (*s != '\0') // move pointer
s++;
int count = 0;
while (++count <= n)
*s++ = *t++;
*(++s) = '\0';
}
int main () {
char *t = " Bluish";
char *s = "Red and";
// before concat
printf ("Before concat: %s\n", s);
strncat(s, t, 4);
// after concat
printf ("After concat: %s\n", s);
return 0;
}
It compiles and runs fine...just that it doesn't concatenate at all!
Greatly appreciate any feedback...thanks!
It seems like you redefine s pointer with your malloc, since you've done it, it doesn't points to your first concatenated string.
First of all function return type should be char*
char* strncat (char *s, char *t, int n)
After, I think you should create local char pointer.
char* localString;
use malloc for allocate space with this pointer
localString = malloc (n + strlen(s) + 1);
and you don't need to make type cast here, cuz malloc do it itself
in fact, you should use your size parameter (n) here, not strlen(t)
and after doing all concatenation operation with this pointer return it
return localString
I have a character array of length 32 and would like to take certain charcters out of it.
for example
111111000000000000000000111111 <32 chars
I would like to take chars 0-6 which would be 111111
Or even take chars 26-31 which would be 111111
char check_type[32];
Above is how I'm declaring.
What I would like to be able to do is define a function or use a function that takes that starting place, and end character.
Ive looked at many ways like using strncpy and strcpy but found no way yet.
I would simply wrap strncpy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Creates a sub-string of range [start, end], return value must be freed */
char *substr(char *src, size_t start, size_t end)
{
size_t sub_len = end - start + 1;
char * new_str = malloc(sub_len + 1); /* TODO: check malloc's return value */
strncpy(new_str, src, sub_len);
new_str[sub_len] = '\0'; /* new_str is of size sub_len + 1 */
return new_str;
}
int main(void)
{
char str[] = "111111000000000000000000111111";
char *sub_str = substr(str, 0, 5);
puts(sub_str);
free(sub_str);
return EXIT_SUCCESS;
}
Output:
111111
Use memcpy.
// Stores s[from..to) in sub.
// The caller is responsible for memory allocation.
void extract_substr(char const *s, char *sub, size_t from, size_t to)
{
size_t sublen = to - from;
memcpy(sub, s + from, sublen);
sub[sublen] = '\0';
}
Sample:
char *substr(char *source, int startpos, int endpos)
{
int len = endpos - startpos + 2; // must account for final 0
int i = 0;
char *src, *dst;
char *ret = calloc(len, sizeof(char));
if (!ret)
return ret;
src = source + startpos;
dst = ret;
while (i++ < len)
*dst++ = *src++;
*dst = 0;
return ret;
}
Of course, free the return code when you don't need it anymore. And you notice this function will not check for the validity of endpos vs startpos.
First define the required interface...perhaps:
int substring(char *target, size_t tgtlen, const char *source, size_t src_bgn, size_t src_end);
This takes a destination (target) array where the data will be copied, and is given its length. The data will come from the source array, between positions src_bgn and src_end. The return value will be -1 for an error, and the length of the output (excluding the terminating null). If the target string is too short, you will get an error.
With that set of details in place, you can implement the body fairly easily, and strncpy() might well be appropriate this time (it often isn't).
Usage (based on your question):
char check_type[32] = "111111000000000000000000111111";
char result1[10];
char result2[10];
if (substring(result1, sizeof(result1), check_type, 0, 6) <= 0 ||
substring(result2, sizeof(result2), check_type, 26, 31) <= 0)
...something went wrong...
else
...use result1 and result2...
Check this:
char* Substring(char *string, int len, int start, int end) {
/*
Creates a substring from a given string.
Args:
string: The string whose substring you need to find.
len: The length of the string.
start: The start position for the substring.
end: The end position of the substring (inclusive).
Returns:
substring: (of type char*) which is allocated on the heap.
NULL: on error.
*/
// Check that the start and end position are valid.
// If not valid, then return NULL.
if (start < 0 || start >= len || end < 0 || end >= len) {
return NULL;
}
// Allocate memory to return the substring on the heap.
char *substring = malloc(sizeof(char) * (end - start + 2));
int index = 0, i;
for (i = start; i <= end; i++) {
substring[index] = string[i];
index++;
}
// End with a null character.
substring[index] = '\0';
return substring;
}
int main() {
char str[] = "11111100000000000000000000111111";
printf("%s\n", Substring(str, strlen(str), 0, 5));
printf("%s\n", Substring(str, strlen(str), 26, 31));
}