The question is simple but the C language doesn't provide us with a useful library:
Suppose that we have this string:
char *request = "GET /websiteos/example_of_a_simple_html_page.htm HTTP/1.1\r\n";
How can I get the following string:
/websiteos/example_of_a_simple_html_page.htm
The string I’m looking for is found between 2 spaces. The problem is that each time I will have a new request line, so I don't know the size of the string.
I thought I'd proceed like this, but it doesn't work:
char * getTheResource(char *request){
char c;
int i=4;
char *resource=(char *)malloc(20);
while (request[i] != ' ')
{ strcat(resource, request[i]);
i++;
}
return resource;
}
int main( int n , char *arg[] )
{
char *request = "GET /websiteos/example_of_a_simple_html_page.htm HTTP/1.1\r\nHost: help.websiteos.com\r\n\r\n";
char *res =getTheResource(request);
printf("the ressource is :%s\n",res);
}
I'm getting a compilation error:
In function ‘getTheResource’:
example.c:19:3: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast [enabled by default]
strcat(resource, request[i]);
So how can I solve this problem?
Consider using strchr function to find pointer to first space in your string, then pass this pointer increased by one to strchr again to get pointer to second space in your string, then copy the range from first pointer to second into output and add a null terminator.
#include <string.h>
#include <stdio.h>
void f(const char* s, char* res) {
char* l = strchr(s, ' ');
char* r = strchr(l + 1, ' ');
memcpy(res, l + 1, r - l);
res[r - l - 1] = '\0';
}
int main() {
const char* s = "sdfasdfasdf sadf sdfasdf";
char res[1024];
f(s, res);
printf("%s\n", res);
return 0;
}
strcat(resource, request[i]);
It is wrong because request[i] is of type char and strcat require char * .
You can assign character to resource at that index using = operator instead:
int j = 0;
while(request[i] != ' ' && j < 19){ // Or the size you allocate to your pointer
resource[j] = request[i];
i++;
j++;
}
resource[j] = '\0';
EDIT-
You can also make use of strtok. Use space as delimiter and get the string you want after tokenizing (But declare request as char request[] = "your string"; in main).
You have several problems with your code.
The strcat should not be used for copying a single character, use assignment instead.
You should always check the return from your allocations - in this case use calloc() instead of malloc() so the buffer gets initialized with NUL characters as well as allocated.
Your while loop is very dangerous as it assumes the string has at least one ' '. You should make sure to always check so you don't run off the end of your string.
If the request string is too short you will have trouble so check for the length of the input string.
You must ensure that you have enough space to hold the new string and not to overrun the new string buffer. So you need a #define to tell you how much you can fit into the new buffer.
Keep in mind that if you use the getTheResource() you must free() the memory if you are not planning on exiting the application. It is not required here because you are exiting the application but in case you use the getTheResource() somewhere else in your code you should free the returned buffer when done with it.
It is good practice to free() your memory anyway because it will help you discover errors that you didn't expect - like overrunning the resource string buffer length might not show up as an error unless you try to free the buffer and then the OS complains. Something that will get you later after you think everything is running OK (but it isn't).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NEW_STRING_MAX_SIZE 100
char *getTheResource(char *request) {
int i=4, j=0;
char *resource;
// validate input string is not NULL
if ( !request )
return NULL;
// allocate and initialize buffer to hold new string
if ( !( resource = (char *)calloc(1, NEW_STRING_MAX_SIZE) ) )
return NULL;
// validate input string is at least 4-characters
if ( strlen( request ) <= i )
return resource;
// loop through old string copying to new string char by char
while ( request[i] != '\0' && request[i] != ' ' && j < NEW_STRING_MAX_SIZE-1 )
resource[j++] = request[i++]; // do a character assignment rather than strcat
return resource;
}
int main( int n , char *arg[] )
{
char *request = "GET /websiteos/example_of_a_simple_html_page.htm HTTP/1.1\r\nHost: help.websiteos.com\r\n\r\n";
char *res = getTheResource(request);
printf("the ressource is :%s\n",res);
if ( res != NULL )
free( res );
}
Related
For some functions for string manipulation, I try to rewrite the function output onto the original string. I came up with the general scheme of
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *char_repeater(char *str, char ch)
{
int tmp_len = strlen(str) + 1; // initial size of tmp
char *tmp = (char *)malloc(tmp_len); // initial size of tmp
// the process is normally too complicated to calculate the final length here
int j = 0;
for (int i = 0; i < strlen(str); i++)
{
tmp[j] = str[i];
j++;
if (str[i] == ch)
{
tmp[j] = str[i];
j++;
}
if (j > tmp_len)
{
tmp_len *= 2; // growth factor
tmp = realloc(tmp, tmp_len);
}
}
tmp[j] = 0;
char *output = (char *)malloc(strlen(tmp) + 1);
// output matching the final string length
strncpy(output, tmp, strlen(tmp));
output[strlen(tmp)] = 0;
free(tmp); // Is it necessary?
return output;
}
int main()
{
char *str = "This is a test";
str = char_repeater(str, 'i');
puts(str);
free(str);
return 0;
}
Although it works on simple tests, I am not sure if I am on the right track.
Is this approach safe overall?
Of course, we do not re-write the string. We simply write new data (array of the characters) at the same pointer. If output is longer than str, it will rewrite the data previously written at str, but if output is shorter, the old data remains, and we would have a memory leak. How can we free(str) within the function before outputting to its pointer?
A pair of pointers can be used to iterate through the string.
When a matching character is found, increment the length.
Allocate output as needed.
Iterate through the string again and assign the characters.
This could be done in place if str was malloced in main.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *char_repeater(char *str, char ch)
{
int tmp_len = strlen(str) + 1; // initial size of tmp
char *find = str;
while ( *find) // not at terminating zero
{
if ( *find == ch) // match
{
tmp_len++; // add one
}
++find; // advance pointer
}
char *output = NULL;
if ( NULL == ( output = malloc(tmp_len)))
{
fprintf ( stderr, "malloc peoblem\n");
exit ( 1);
}
// output matching the final string length
char *store = output; // to advance through output
find = str; // reset pointer
while ( *find) // not at terminating zero
{
*store = *find; // assign
if ( *find == ch) // match
{
++store; // advance pointer
*store = ch; // assign
}
++store; // advance pointer
++find;
}
*store = 0; // terminate
return output;
}
int main()
{
char *str = "This is a test";
str = char_repeater(str, 'i');
puts(str);
free(str);
return 0;
}
For starters the function should be declared like
char * char_repeater( const char *s, char c );
because the function does not change the passed string.
Your function is unsafe and inefficient at least because there are many dynamic memory allocations. You need to check that each dynamic memory allocation was successful. Also there are called the function strlen also too ofhen.
Also this code snippet
tmp[j] = str[i];
j++;
if (str[i] == ch)
{
tmp[j] = str[i];
j++;
}
if (j > tmp_len)
//...
can invoke undefined behavior. Imagine that the source string contains only one letter 'i'. In this case the variable tmp_len is equal to 2. So temp[0] will be equal to 'i' and temp[1] also will be equal to 'i'. In this case j equal to 2 will not be greater than tmp_len. As a result this statement
tmp[j] = 0;
will write outside the allocated memory.
And it is a bad idea to reassign the pointer str
char *str = "This is a test";
str = char_repeater(str, 'i');
As for your question whether you need to free the dynamically allocated array tmp
free(tmp); // Is it necessary?
then of course you need to free it because you allocated a new array for the result string
char *output = (char *)malloc(strlen(tmp) + 1);
And as for your another question
but if output is shorter, the old data remains, and we would have a
memory leak. How can we free(str) within the function before
outputting to its pointer?
then it does not make a sense. The function creates a new character array dynamically that you need to free and the address of the allocated array is assigned to the pointer str in main that as I already mentioned is not a good idea.
You need at first count the length of the result array that will contain duplicated characters and after that allocate memory only one time.
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * char_repeater( const char *s, char c )
{
size_t n = 0;
for ( const char *p = s; ( p = strchr( p, c ) ) != NULL; ++p )
{
++n;
}
char *result = malloc( strlen( s ) + 1 + n );
if ( result != NULL )
{
if ( n == 0 )
{
strcpy( result, s );
}
else
{
char *p = result;
do
{
*p++ = *s;
if (*s == c ) *p++ = c;
} while ( *s++ );
}
}
return result;
}
int main( void )
{
const char *s = "This is a test";
puts( s );
char *result = char_repeater( s, 'i' );
if ( result != NULL ) puts( result );
free( result );
}
The program output is
This is a test
Thiis iis a test
My kneejerk reaction is to dislike the design. But I have reasons.
First, realloc() is actually quite efficient. If you are just allocating a few extra bytes every loop, then chances are that the standard library implementation simply increases the internal bytecount value associated with your memory. Caveats are:
Interleaving memory management.Your function here doesn’t have any, but should you start calling other routines then keeping track of all that becomes an issue. Anything that calls other memory management routines can lead to the next problem:
Fragmented memory.If at any time the available block is too small for your new request, then a much more expensive operation to obtain more memory and copy everything over becomes an issue.
Algorithmic issues are:
Mixing memory management in increases the complexity of your code.
Every occurrence of c invokes a function call with potential to be expensive. You cannot control when it is expensive and when it is not.
Worst-case options (char_repeater( "aaaaaaaaaa", 'a' )) trigger worst-case potentialities.
My recommendation is to simply make two passes.
This passes several smell tests:
Algorithmic complexity is broken down into two simpler parts:
counting space required, and
allocating and copying.
Worst-case scenarios for allocation/reallocation are reduced to a single call to malloc().
Issues with very large strings are reduced:
You need at most space for 2 large strings (not 3, possibly repeated)
Page fault / cache boundary issues are similar (or the same) for both methods
Considering there are no real downsides to using a two-pass approach, I think that using a simpler algorithm is reasonable. Here’s code:
#include <stdio.h>
#include <stdlib.h>
char * char_repeater( const char * s, char c )
{
// FIRST PASS
// (1) count occurances of c in s
size_t number_of_c = 0;
const char * p = s;
while (*p) number_of_c += (*p++ == c);
// (2) get strlen s
size_t length_of_s = p - s;
// SECOND PASS
// (3) allocate space for the resulting string
char * dest = malloc( length_of_s + number_of_c + 1 );
// (4) copy s -> dest, duplicating every occurance of c
if (dest)
{
char * d = dest;
while (*s)
if ((*d++ = *s++) == c)
*d++ = c;
*d = '\0';
}
return dest;
}
int main(void)
{
char * s = char_repeater( "Hello world!", 'o' );
puts( s );
free( s );
return 0;
}
As always, know your data
Whether or not a two-pass approach actually is better than a realloc() approach depends on more factors than what is evident in a posting on the internet.
Nevertheless, I would wager that for general purpose strings that this is a better choice.
But, even if it isn’t, I would argue that a simpler algorithm, splitting tasks into trivial sub-tasks, is far easier to read and maintain. You should only start making tricky algorithms only if you have use-case profiling saying you need to spend more attention on it.
Without that, readability and maintainability trumps all other concerns.
I'm trying to make a function that cut a part of a string so that at the desired position, and for the desired length, it removes the part.
I'm getting SIGSEGV error (segmentation fault) while running with the debugger at the "Str[Pos] = 0". I don't understand why because I'm just trying to make the char pointer at this specific position set to 0 or '\0' so that it acts like it is the end of the array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
char * String = malloc(512);
String = "Blobfish is the best creature ever made by nature";
CutString(String, 3, 4);
print("%s", String);
}
bool CutString(char * Str, int Pos, int Size)
{
int StrLen = strlen(Str);
printf("After4\n");
if (Size < 1 || Size + Pos > StrLen) return true;
printf("After4.1\n");
char * StrPos = Str + Pos + Size;
printf("After4.2\n");
printf("%s", StrPos);
Str[Pos] = 0;
printf("After4.3\n");
strcat(Str, StrPos);
printf("After4.4\n");
return false;
}
Thank you in advance for your help and take care in these times,
Jules.
The function is invalid but it is enough to point to that the program in any case has undefined behavior because it tries to modify a string literal and modifying a string literal results in undefined behavior.
char * String = malloc(512);
String = "Blobfish is the best creature ever made by nature";
CutString(String, 3, 4);
//...
Moreover there is a memory leak because at first a memory was allocated and pointer to the memory was assigned to the pointer String. And then the pointer String was reassigned with the address of a string literal. So the address of the allocated memory is lost.
As for the function then it can be defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
char * CutString( char * s, size_t pos, size_t n )
{
size_t length = strlen( s );
if ( pos < length )
{
n = length - pos < n ? length - pos : n;
memmove( s + pos, s + pos + n, length - pos - n + 1 );
}
return s;
}
int main(void)
{
char s[] = "Blobfish is the best creature ever made by nature";
puts( s );
puts( CutString( s, 3, 4 ) );
return 0;
}
The program output is
Blobfish is the best creature ever made by nature
Bloh is the best creature ever made by nature
Pay attention to that there is no great sense when the function has the return type bool. It is much better when such a function returns pointer to the string itself after its modification. All standard C string functions follow this convention.
Code is attempting to change a string literal which is undefined behavior.
Instead, modify allocated memory.
char * String = malloc(512);
// The below only copies the pointer to the string literal, not the string contents.
// String = "Blobfish is the best creature ever made by nature";
strcpy(String, "Blobfish is the best creature ever made by nature");
I can't quite tell exactly what you are trying to do with this function. But I have highlighted a couple problems:
This will cause you problems. As Size + Pos should always be bigger than StrLen. Since Strlen should be equal to size.
if (Size < 1 || Size + Pos > StrLen) return true;
Rewrite it as:
if (Size < 1 || Pos > StrLen)
{
return true;
}
Also, this definition is not correct. This will assign the pointer to a location you do not want.
char * StrPos = Str + Pos + Size;
Correct this to :
char * StrPos = &Str[Pos];
Once you cut the string I don't know what you are trying to do. I implemented and ran the program to simply append the cut string to end of the input and print it. You can see this here:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool CutString(char * Str, int Pos, int Size)
{
int StrLen = strlen(Str);
if (Size < 1 || Pos > StrLen)
{
return true;
}
char * StrPos = &Str[Pos];
printf("%s\n", StrPos);
strcat(Str, StrPos);
printf("%s", Str);
return false;
}
int main()
{
char input[26] = "WhatDoesThisDo?";
CutString(input,5,14);
return 0;
}
i've done a function that inverse a String(array of character) given in parameter , but it's not working , any idea why ?
I'm getting something like this : æIGt(Kt$0#
thanks you
#include <stdio.h>
#include <string.h>
char *
inverse(char *s)
{
int i, taille = strlen(s);
char r[taille];
for (i = 0 ; i < taille ; i++)
{
r[i] = s[taille - i - 1];
}
r[i] = '\0';
return r;
}
int
main()
{
char s[] = "kira";
char *r = inverse(s);
printf("%s",r);
return 1;
}
You are returning a pointer to a local variable. That variable gets destroied when the function inverse returns, so accessing the pointer after the function exits will return invalid data.
It's slightly hard to tell from you question, because you haven't given any outputs, but my best guess is that it's because your returning a pointer to an item on the stack, which will get over-written by the next call, in your case printf. You need to pass inverse a place to put its answer. Try this instead:
#include <stdio.h>
#include <string.h>
void inverse(char *s, char *r)
{
int i,taille=strlen(s);
for(i=0;i<taille;i++)
{
r[i]=s[taille-i-1];
}
r[i]='\0';
}
int main()
{
char s[] = "kira";
char r[sizeof(s)];
inverse(s, r);
printf("%s",r);
return 1;
}
Another standard approach to reversing a string uses pointers to work from both the beginning and end of the string swapping two characters with each iteration. It swaps the original string in place (make a copy if you need to preserve the original, or pass a second string and place the reversed string in there)
/** strrevstr - reverse string, swaps 2 chars per-iteration.
* Takes valid string and reverses, original is not preserved.
* If 's' is valid and non-empty, returns pointer to 's',
* returns NULL otherwise.
*/
char *strrevstr (char *s)
{
if (!s || !*s) { /* validate string is not NULL and non-empty */
printf ("strrevstr() error: invalid string\n");
return NULL;
}
char *begin = s; /* pointers to beginning and end, and tmp char */
char *end = begin + strlen (s) - 1;
char tmp;
while (end > begin) /* swap both beginning and end each iteration */
{
tmp = *end;
*end-- = *begin;
*begin++ = tmp;
}
return s;
}
As you can tell, there are a number of ways to approach the problem, with this and the other answers provided, you should be able to tailor a solution to meet your needs.
There are advantages and disadvantages to every approach. There is nothing wrong with dynamically allocating a new block of memory to hold the reversed string, it just adds an additional responsibility to (1) preserve a pointer to the starting address for the new block so (2) it can be freed when no longer needed. If you need to preserve the original string, passing a pointer to an character array of sufficient size to hold the reversed string is another option preserve the original.
Look over all the answers and let me know if you have any questions.
I have writen a code to split the string with multiple char delimiter.
It is working fine for first time of calling to this function
but i calling it second time it retuns the correct word with some unwanted symbol.
I think this problem occurs because of not clearing the buffer.I have tried a lot but cant solve this. please help me to solve this problem.
char **split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist= malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
arraylist[i]=malloc(sizeof(buf));
arraylist[i]=buf;
i++;
loc = loc+length;
loc1 = loc;
}
return arraylist;
}
called this function first time
char **splitdetails = split("100000000<delimit>0<delimit>hellooo" , "<delimit>");
It gives
splitdetails[0]=100000000
splitdetails[1]=0
splitdetails[2]=hellooo
but i called this second time
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
splitdetails[0]=20000000��������������������������
splitdetails[1]=10����
splitdetails[2]=testing
Update:-
thanks to #fatelerror. i have change my code as
char** split(char *phrase, char *delimiter) {
int i = 0;
char **arraylist = malloc(10 *sizeof(char *));
char *loc1=NULL;
char *loc=NULL;
loc1 = phrase;
while (loc1 != NULL) {
loc = strstr(loc1, delimiter);
if (loc == NULL) {
arraylist[i]=malloc(strlen(loc1) + 1);
strcpy(arraylist[i], loc1);
break;
}
char *buf = malloc(sizeof(char) * 256); // memory for 256 char
int length = strlen(delimiter);
strncpy(buf, loc1, loc-loc1);
buf[loc - loc1] = '\0';
arraylist[i]=malloc(strlen(buf));
strcpy(arraylist[i], buf);
i++;
loc = loc+length;
loc1 = loc;
}
}
In the caller function, i used it as
char *id
char **splitdetails = split("20000000<delimit>10<delimit>testing" , "<delimit>");
id = splitdetails[0];
//some works done with id
//free the split details with this code.
for(int i=0;i<3;i++) {
free(domaindetails[i]);
}free(domaindetails);
domaindetails=NULL;
then i called the same for the second as,
char **splitdetails1= split("10000000<delimit>1000<delimit>testing1" , "<delimit>");
it makes error and i can't free the function.
thanks in advance.
Your problem boils down to three basic things:
sizeof is not strlen()
Assignment doesn't copy strings in C.
strncpy() doesn't always nul-terminate strings.
So, when you say something like:
arraylist[i]=malloc(sizeof(loc1));
arraylist[i]=loc1;
thisdoes not copy the string. The first one allocates the size of loc1, which is a char *. In other words, you allocated the size of a pointer. You want to allocate storage to store the string, i.e. using strlen():
arraylist[i]=malloc(strlen(loc1) + 1);
Note the + 1 as well, because you also need room for the nul-terminator. Then, to copy the string you want to use strcpy():
strcpy(arraylist[i], loc1);
The way you had it was just assigning a pointer to your old string (and in the process leaing the memory you had just allocated). It's also common to use strdup() which combines both of these steps, i.e.
arraylist[i] = strdup(loc1);
This is convenient but strdup() is not part of the official C library. You need to assess the portability needs of your code before you consider using it.
Additionally, with strncpy(), you should be aware that it does not always nul-terminate:
strncpy(buf, loc1, loc-loc1);
This copies less bytes than were in the original string and doesn't terminate buf. Thus, it's necessary to include a nul terminator yourself:
buf[loc - loc1] = '\0';
This is the root cause of what you are seeing with the garbage. Since you didn't nul terminate, C doesn't know where your string ends and so it keeps on reading whatever happens to be in memory.
Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}