String handling in c - c

Here is my code
char* a[10];
a[0]="'example'";
char* p;
p=strstr(a[0],"'");
I know if strstr can find the ' it returns a pointer which points to first character which is '. I want to take the value between two ' and save it in a[1]. how should I do that?
As a result
a[1] is "example".

strchr() seems a more appropriate choice that strstr().
Use the result of first strchr(), + 1, as the argument to a subsequent strchr() and then malloc() and strcpy() or sprintf() into a[1]:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* a[10];
char* p;
a[0] = "'example'";
p = strchr(a[0], '\'');
if (p)
{
char* q = strchr(++p, '\'');
if (q)
{
a[1] = malloc((q - p) + 1);
if (a[1])
{
sprintf(a[1], "%.*s", q - p, p);
printf("[%s]\n", a[1]);
}
}
}
return 0;
}
Storing pointers to string literals and malloc() data into the same array seems a dangerous thing to do. You must free() dynamically allocated memory, but only dynamically allocated memory. The code will need to know what elements in a are pointing at dynamically allocated memory, and must be free()d, and those that are not.
Initialise a to all NULLs, so it is known what elements are populated:
char* a[10] = { NULL };
and calling free() on a NULL pointer is safe (does nothing).

Just find the next occurrence of ' and copy the substring:
char* a[10];
a[0]="'example'";
char* p, *q;
p=strstr(a[0],"'");
if (p) {
q = strstr(p+1, "'");
if (q) {
size_t len = (size_t)(q - p);
char *sub = malloc(len + 2);
if (!sub) {
/* Oops */
exit(EXIT_FAILURE); /* Something more sensible rather */
}
memcpy(sub, p, len+1);
sub[len+1] = 0;
a[1] = sub;
}
else {
a[1] = NULL;
}
}
else {
a[1] = NULL;
}
Note that in this case, it would be better to use strchr to find the single character.

Related

Confused between passing strings to a function (C)

Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);

free of malloc inside the function, how to do that?

I create the malloc inside str function and i want to free this malloc variable
#include <stdio.h>
char *str(void)
{
// create the malloc
char *string = malloc(2); // how to free it
*(string + 0) = 'J';
*(string + 1) = 'O';
// return the malloc
return string;
}
int main(void)
{
// print the function
printf("%s, str());
return 0;
}
free(string)
would free it. But to print it as a string you must have the \0 in the end.
Note: You should not free it inside the function if your plan is to return it at the end of the function call. Since that would potentially give rise to undefined behavior.
Correct way of doing things:
char *str(void)
{
// create the malloc
char *string = malloc(3); // how to free it
if(string){
*(string + 0) = 'J';
*(string + 1) = 'O';
*(string + 2) = '\0';
// return the malloc
}
return string;
}
int main(void)
{
// print the function
char *s = str();
if(s)
printf("%s", s);
free(s);
return 0;
}
Incorrect
If you do this, then it would be a memory leak:
int main(void)
{
// print the function
printf("%s", str());
return 0;
}
And if you do this, then you have undefined behavior when you try to print it out.
char *str(void)
{
// create the malloc
char *string = malloc(2); // how to free it
*(string + 0) = 'J';
*(string + 1) = 'O';
// return the malloc
free(string);
return string;
}
int main(void)
{
// print the function
printf("%s", str()); // undefined behavior. A dragon might appear.
return 0;
}
Usually it is better alternative to let the caller provide the buffer to print to; if printing actually was successful could be hinted to via a return value; a new function signature might then look like this:
#include <stdbool.h>
bool str(size_t length, char buffer[length])
{
if(length < 3)
{
// buffer is too short...
return false;
}
buffer[0] = 'J';
buffer[1] = 'O';
buffer[2] = 0; // terminating null character, which you ommitted!
}
Note that the length specifier in the array parameter is ignored (function parameters only!), the definition is equivalent to char buffer[] or char* buffer; still specifying the length can serve to tell a user what kind of parameter actually is expected (-> self documenting code); note, too, that this only applies for the outer-most dimenstion (in char[12][10] the 12 is ignored but not the 10, the parameter type is equivalent to char(*)[10] which is a pointer to an array of length 10).
A user then is free where to allocate the string, dynamically on heap or on stack:
int main(void)
{
char stack[3];
if(str(sizeof(stack), stack))
{
printf("%s", stack);
}
size_t len = 3;
char* heap = malloc(len);
if(!heap) // should always be checked!
{
// allocation failed!
return -1;
}
if(str(len, heap))
{
printf("%s", heap);
}
free(heap);
return 0;
}
If you still want to retain the original signature then you need the returned string twice, once to print it, once to free it – i.e. you need to store it in an intermediate variable to be able to do so:
int main(void)
{
char* s = str(); // store it in a variable!
printf("%s", s); // still need to append the null terminator for!!!
free(s); // now you can free it
return 0;
}
If you don't append the null terminator then you need to explicitly limit the number of characters to print to console:
printf("%.2s", s);
// ^^ (!)

Memory management in replace function

I'm trying to make a replace function in C. I know there are many out there that I could copy, but I decided to make my own function in order to practice.
However, I'm stuck at this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void replace_content(char *rep, char *with, char **text) {
int len_rep = strlen(rep);
int len_with = strlen(with);
char *p = *text;
int new_text_size = 0;
char *new_text = malloc(new_text_size);
do {
if (!strncmp(p, rep, len_rep)) {
new_text_size += len_with;
new_text = (char *) realloc(new_text, new_text_size + 1);
strcat(new_text, with);
p += len_rep;
} else {
new_text_size++;
new_text = (char *) realloc(new_text, new_text_size);
new_text[new_text_size-1] = *p;
p++;
}
} while (*p != '\0');
*text = malloc(new_text_size);
strcpy(*text, new_text);
}
int main() {
printf("Testing a replace function:\n");
char *text =
"<serviceName>\n"
" <label1>a</label1>\n"
" <label2>b</label2>\n"
" <label3>c</label3>\n"
"</serviceName>\n";
printf("Before replace:\n%s", text);
replace_content("serviceName>", "serviceNameResponse>", &text);
printf("After replace:\n%s", text);
return 0;
}
This is the output I'm seeing so far:
Testing a replace function:
Before replace:
<serviceName>
<label1>a</label1>
<label2>b</label2>
<label3>c</label3>
</serviceName>
After replace:
<0�serviceNameRespons
<label1>a</label1>
<label2>b</label2>
<label3>c</label3>
</serviceNameResponse>
My guess is that I'm doing something wrong with dynamic memory, but the more I look into my code the more confused I am.
These two statements are problematic:
new_text = (char *) realloc(new_text, new_text_size + 1);
strcat(new_text, with);
The first problem is that you should never assign back directly to the pointer you reallocate. That is because realloc may fail and return NULL, making you lose the original pointer.
The second problem is that new_text doesn't initially point to a null-terminated string, which makes the call to strcat undefined behavior.
There is also a problem in the else branch:
new_text = (char *) realloc(new_text, new_text_size);
new_text[new_text_size-1] = *p;
Besides the same problem with reassigning back to the pointer being reallocated, you don't terminate the string in new_text.
May the reason is malloc(0) in line 10 char *new_text = malloc(new_text_size);.
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that
can later be successfully passed to free().
I suggest using char *new_text = NULL; instead.

Custom concat function in C with pointer

I try to code my own concatenation function in C without library, but I have issue and I don't know where it comes from.
To do my function I use pointers of char.
This is my Code :
#include <stdio.h>
#include <stdlib.h>
int longueur(char *str)
{
int i =0;
while(str[i] != '\0')
{
i++;
}
return i;
}
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = dest;
free(dest);
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
while(temp[i] != '\0')
{
dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
int main()
{
char *str1 = "World";
char *str2 = "Hello";
concat(str1, str2);
printf("-------------\n%s", str2);
return 0;
}
EDIT
I read all your answer, so I changed my concat function to :
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
dest = (char*) malloc((longStr1 + longStr2)* sizeof(char) + sizeof(char));
while(dest[i] != '\0')
{
dest[i] = dest[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
Now I don't have issue but my code only display "Hello"
In addition to all the good comments and solutions: realloc can give you a different pointer and you must return that pointer. So your function signature should be:
void concat(char* source, char** dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = *dest, *temp2;
if ((temp2 = realloc(dest, ((longStr1 + longStr2)+1))==NULL) return;
*dest= temp2;
while(temp[i] != '\0')
{
*dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
*dest[i] = source[j];
i++;
j++;
}
*dest[i] = '\0';
}
..and this assumes the function will only be called with a dest that was allocated with malloc. And sizeof(char) is always 1. (This resulting function is not optimal.)
--EDIT--
Below the correct, optimized version:
void concat(char* source, char** dest)
{
int longSrc = longueur(source);
int longDst = longueur(dest);
char *pDst, *pSrc;
if ((pDst = realloc(*dest, longSrc + longDst + 1))==NULL) return;
if (pDst != *dest) *dest= pDst;
pDst += longSrc;
pSrc= source;
while(pSrc)
*pDst++ = *pSrc++;
*pDst = '\0';
}
In your code
free(dest);
and
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
invokes undefined behavior as none of them use a pointer previously allocated by malloc() or family.
Mostly aligned with your approach, you need to make use of another pointer, allocate dynamic memory and return that pointer. Do not try to alter the pointers received as parameters as you've passed string literals.
That said, you need to have some basic concepts clear first.
You need not free() a memory unless it is allocated through malloc() family.
You need to have a char extra allocated to hold the terminating null.
Please see this discussion on why not to cast the return value of malloc() and family in C..
If your concatenation function allocates memory, then, the caller needs to take care of free()-ing the memory, otherwise it will result in memory leak.
After you have freed dest here:
free(dest);
You cannot use this pointer in following call to realloc:
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
man realloc
void *realloc(void *ptr, size_t size);
The realloc() function changes the size of the memory block
pointed to by ptr to size bytes. (...)
But this pointer is invalid now and you cannot use it anymore. When you call free(dest), the memory dest points to is being freed, but the value of dest stays untouched, making the dest a dangling pointer. Accessing the memory that has already been freed produces undefined behavior.
NOTE:
Even if free(dest) is technically valid when called on pointer to memory allocated by malloc (it is not an error in your function to call free(dest) then), it is incorrect to use this on pointer to literal string as you do in your example (because str2 points to string literal it is an error to pass this pointer to function calling free on it).
Given your original use, perhaps you would find a variant like this useful
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t longueur ( const char * str ) { /* correct type for string lengths */
size_t len = 0;
while (*str++ != '\0') ++len;
return len;
}
char * concat ( const char * first, const char * second ) {
const char * s1 = first ? first : ""; /* allow NULL input(s) to be */
const char * s2 = second ? second : ""; /* treated as empty strings */
size_t ls1 = longueur(s1);
size_t ls2 = longueur(s2);
char * result = malloc( ls1 + ls2 + 1 ); /* +1 for NUL at the end */
char * dst = result;
if (dst != NULL) {
while ((*dst = *s1++) != '\0') ++dst; /* copy s1\0 */
while ((*dst = *s2++) != '\0') ++dst; /* copy s2\0 starting on s1's \0 */
}
return result;
}
int main ( void ) {
const char *str1 = "Hello";
const char *str2 = " World";
char * greeting = concat(str1, str2);
printf("-------------\n%s\n-------------\n", greeting);
free(greeting);
return 0;
}
In this variant, the two inputs are concatenated and the result of the concatenation is returned. The two inputs are left untouched.

strncat implementation?

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

Resources