Manipulating a string and rewriting it by the function output - c

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.

Related

I can't figure out how to use double pointers

I'm trying to use dynamic memory allocation but I can't figure out pointers.
I got the first part down.
void addtext(char **wordarray)
{
char word[N];
char endword[N] = "end";
int i=0;
int words=0;
while (scanf("%19s", word), strcmp(word,endword))
{
words++;
wordarray = realloc(wordarray, words*sizeof(char *));
wordarray[words-1] = malloc (N*sizeof(char));
strcpy(wordarray[words-1], word);
}
for (i=0; i<words; i++)
printf("%s\n", wordarray[i]);
return ;
}
But I'm having trouble when I try to call the same array in a different function.
void savetext(char **wordarray)
{
FILE *savedtext;
int i=0;
savedtext = fopen("Saved Text.txt","wt");
while(wordarray[i][0]!= '\0')
{
fputs(wordarray[i++],savedtext);
fputs(" ",savedtext);
}
return ;
}
My main function looks something like this:
int main (void)
{
char **wordarray;
addtext(wordarray);
savetext(wordarray);
return 0;
}
The second part of the code is obviously wrong, but I'm not sure how to exactly how to call those functions. My previous program didn't use any memory allocation so I didn't bother with pointers.I'm really new to c so any help would be appreciated.
Oh boy. Well, you have two big problems.
First, you never allocated the first wordarray. At the very least malloc it once:
char **wordarray = malloc(1);
Or even better, use malloc instead of realloc the first time (and initialize wordarray with 0!):
wordarray = wordarray ? realloc(wordarray, words * sizeof(char *))
: malloc(words * sizeof(char *));
Second, your addtext function is receiving a copy of this array, and doing stuff with it. Whatever the stuff is, it won't be saved in your wordarray outside, in main. What you need to do is pass a pointer to the array in your function, and edit the main object through that:
void addtext(char ***wordarray)
{
// ...
}
And lastly, you have some very big performance problems, allocating buffers so often. Use a proper growing vector implementation, or if you insist on writing your own at the very least grow it by doubling the size, or even better count the words and allocate the correct size.
Also your end string is arbitrarily allocated of length N, whatever that is. You don't need that, you already know the length. In fact the string is already in the read-only section of your binary, simply get a pointer to it:
const char *endword = "end";
Perhaps refactor your program to make the string creation its own function, and for symmetry, return storage of the string as its own function.
const int STRING_SIZE = 80;
void createString(char ** strPtr, int stringSize);
void freeString(char * strPtr);
int main(int argc, char ** argv) {
char * strValue = NULL;
createString(&strValue, STRING_SIZE);
// ... do stuff ...
freeString(strValue);
}
//
// end of main
//
void createString(char ** strPtr, int stringSize) {
//
// uses pass-by-reference to return *strPtr with allocated storage
//
*strPtr = (char *) calloc(stringSize, sizeof(char));
}
void freeString(char * strPtr) {
if(strPtr == NULL) return;
free(strPtr);
strPtr = NULL;
}
For starters the program has undefined behavior at least because the pointer wordarray was not initialized and has an indeterminate value
char **wordarray;
and this indeterminate value is used in a call of the function realloc in the function addtext
wordarray = realloc(wordarray, words*sizeof(char *));
Moreover the pointer is passed to the function addtext by value. That is the function deals with a copy of the value of the pointer. So changing the copy does not influence on the value stored in the original pointer. The original pointer in main will stay unchanged.
You need to pass the pointer by reference through a pointer to it.
Another problem of the function is that the number of stored strings will not be known outside the function addtext. You need at least append the array with a null pointer that will be used as a sentinel value.
Also this condition in the while loop within the function savetext
while(wordarray[i][0]!= '\0')
does not make a sense because within the function addtext you stop entering strings when the user will enter the string "end".
while (scanf("%19s", word), strcmp(word,endword))
^^^^^^^^^^^^^^^^^^^^
So it is not necessary that the preceding entered string is an empty string.
Here is a demonstrative program that shows how for example the function addtext can be declared and defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
size_t addtext( char ***wordarray )
{
char word[N];
const char *sentinel = "end";
size_t n = 0;
int success = 1;
while ( success && scanf( "%19s", word ) == 1 && strcmp( word, sentinel ) != 0 )
{
char **tmp = realloc( *wordarray, ( n + 1 ) * sizeof( char * ) );
success = tmp != NULL;
if ( success )
{
++n;
*wordarray = tmp;
( * wordarray )[n-1] = malloc( strlen( word ) + 1 );
if ( ( *wordarray )[n-1] ) strcpy( ( *wordarray )[n-1], word );
}
}
return n;
}
int main(void)
{
char **wordarray = NULL;
size_t n = addtext( &wordarray );
for ( size_t i = 0; i < n; i++ )
{
if ( wordarray[i] != NULL ) puts( wordarray[i] );
}
for ( size_t i = 0; i < n; i++ )
{
free( wordarray[i] );
}
free( wordarray );
return 0;
}
If to enter the following sequence of strings
one
two
three
end
then the program output will be
one
two
three
Correspondingly the declaration of the function savetext should be changed. There is not sense in this case to pass the pointer wordarray to the function by reference because the pointer itself is not changed within the function. Also you need to pass the number of elements in the allocated array, So the function declaration can look at least like
void savetext( char **wordarray, size_t n );

Extracting web addresses from a string in C

I have trouble with my code and I need your help! What I need to do is to write a function that will extract the web address that starts from www. and ends with .edu from an inputted string. The inputted string will have no spaces in it so scanf() should work well here.
For example:
http://www.school.edu/admission. The extracted address should be www.school.edu.
This is what I came up with so far, it obviously didn't work, and I can't think of anything else unfortunately.
void extract(char *s1, char *s2) {
int size = 0;
char *p, *j;
p = s1;
j = s2;
size = strlen(s1);
for(p = s1; p < (s1 + size); p++) {
if(*p == 'w' && *(p+1) == 'w' && *(p+2) == 'w' && *(p+3) == '.'){
for(p; p < (p+4); p++)
strcat(*j, *p);
}
else if(*p=='.' && *(p+1)=='e' && *(p+2)=='d' && *(p+3)=='u'){
for(p; (p+1) < (p+4); p++)
strcat(*j, *p);
}
}
size = strlen(j);
*(j+size+1) = '\0';
}
The function has to use pointer arithmetic. The errors I get have something to do with incompatible types and casting. Thanks ahead!
So the most trivial approach might be:
#include <stdio.h>
int main(void)
{
char str[1000];
sscanf("http://www.school.edu/admission", "%*[^/]%*c%*c%[^/]", str);
puts(str);
}
Now, here goes the fixed code:
#include <stdio.h>
#include <string.h>
void extract(char *s1, char *s2) {
size_t size = strlen(s1), i = 0;
while(memcmp(s1 + i, "www.", 4)){
i++;
}
while(memcmp(s1 + i, ".edu", 4)){
*s2++ = *(s1 + i);
i++;
}
*s2 = '\0';
strcat(s2, ".edu");
}
int main(void)
{
char str1[1000] = "http://www.school.edu/admission", str2[1000];
extract(str1, str2);
puts(str2);
}
Note that s2 must be large enough to contain the extracted web address, or you may get a segfault.
This is an easy solution for your problem:
char* extract(char *s1) {
char* ptr_www;
char* ptr_edu;
int len ;
char* s2;
ptr_www = strstr(s1,"www");
ptr_edu = strstr(s1,".edu");
len = ptr_edu -ptr_www + 4;
s2 = malloc (sizeof(char)*len+1);
strncpy(s2,ptr_www,len);
s2[len] = '\0';
printf ("%s",s2);
return s2;
}
There is a lot wrong unfortunately. Your compilation is failing because you pass a char to strcat when it expects a char*. Even if it did compile though it would crash.
for(p = s1; p < (s1 + size); p++) {
// This if statement will reference beyond s1+size when p=s1+size-2. Consequently it may segfault
if(*p=='w' && *(p+1)=='w' && *(p+2)=='w' && *(p+3)=='.') {
for(p; p < (p+4); p++) // This is an infinite loop
// strcat concatenates one string onto another.
// Dereferencing the pointer makes no sense.
// This is the likely causing your compilation error.
// If this compiled it would almost certainly segfault.
strcat(*j, *p);
}
// This will also reference beyond s1+size. Consequently it may segfault
else if(*p=='.' && *(p+1)=='e' && *(p+2)=='d' && *(p+3)=='u') {
for(p; (p+1) < (p+4); p++) // This is also an infinite loop
// Again strcat expects 2x char* (aka. strings) not 2x char
// This will also almost certainly segfault.
strcat(*j, *p);
}
}
// strlen() counts the number of chars until the first '\0' occurrence
// It is never correct to call strlen() to determine where to add a '\0' string termination character.
// If the character were actually absent this would almost certainly result in a segfault.
// As it is strcat() (when called correctly) will add the terminator anyway.
size = strlen(j);
*(j+size+1) = '\0';
EDIT: This seems like a homework question, so I thought it would be more constructive to mention where your current code is going wrong, so you can recheck your knowledge in those areas.
The answer to your exact question is it doesn't compile because you dereference the string and hence pass 2x char instead of char* to strcat().

Removing whitespace from a character array in C language

Can someone please let me know where the problem is and how to correct it.
The function is required to remove all whitespace from a string which includes ' ', '\t' and '\n' The output of the function should be a copy of the input string but with all of whitespace removed. The function prototype should stay the same and void.
void removeWS(char *strNoSpace, const char *strWithSpace)
{
int i, j;
stringNoSpace = malloc(strlen(strWithSpace) + 1);
for(i = 0, j = 0; stringWithSpace[i] != '\0'; i++, j++){
if (isspace((char) strWithSpace[i]) != 0){
strNoSpace[j++] = strWithSpace[i];
}
}
}
Stripped down to the actual issue:
void removeWS(char *strNoSpace, const char *strWithSpace)
{
strNoSpace = malloc(strlen(strWithSpace) + 1);
// ...
}
// ....
char* paramStrNoSpace = NULL;
char* paramStrWithSpace = "...";
removeWS(paramStrNoSpace, paramStrWithSpace);
Now strNoSpace is a copy of paramStrNoSpace It points to the same memory, which in this case is NULL. Then inside your function you change strNoSpace to something, malloc() returns. Now strNoSpace is something different to NULL, while paramStrNoSpace is still NULL, because strNoSpace was a copy of that pointer.
A simple soulution could be to pass a pointer to a pointer instead:
void removeWS(char **strNoSpace, const char *strWithSpace)
{
*strNoSpace = malloc(strlen(strWithSpace) + 1);
// ...
}
// ....
char* paramStrNoSpace = NULL;
char* paramStrWithSpace = "...";
removeWS(&paramStrNoSpace, paramStrWithSpace);
Now strNoSpace points to the exact position, where the pointer paramStrNoSpace is stored. Whenever you modify *strNoSpace, you actually modify paramStrNoSpace now.
The downside of that approach is, that you will loose track of your memory allocations sooner or later, when functions just allocate and return new memory. The rule of thumb is: whoever allocates memory, is also responsible to free it. Therefore I think a better interface would expect the caller to allocate enough memory for this function:
void removeWS(char *strNoSpace, ind strNoSpaceMaxSize, const char *strWithSpace)
{
// ...
}
// ....
char* paramStrWithSpace = "...";
char* paramStrNoSpace = malloc(strlen(paramStrWithSpace) + 1);
removeWS(paramStrNoSpace, strlen(paramStrWithSpace), paramStrWithSpace);
Now removeWS() does never change strWithSpace. Therefore we can pass it as a simple pointer again, but we have to tell removeWS() the size of the allocated memory block. It has to check while running and stop in case, there is not enough memory.
This can be done inplace as characters are being removed. The pointers to and from advance through the string. When a space is found only from is advanced.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void removeWS( char *strWithSpace)
{
//declare two pointers and set them to first character of strWithSpace
char *to = strWithSpace;
char *from = strWithSpace;
while ( *from) {//when from points to terminating '\0' while will exit
if ( isspace ( *from)) {
from++;//found space character, advance from
continue;//back to top of while
}
*to = *from;//copy from character to to
to++;//advance to
from++;//advance from
}
*to = '\0';//set terminating '\0'
}
int main( int argc, char *argv[])
{
char text[40] = {"text with spaces between the words"};
printf("before %s\n", text);
removeWS( text);
printf("after %s\n", text);
return 0;
}
I see three obvious issues:
You refer to string in the for condition, not strWithSpace
You're only placing NUL ('\0') terminators when you see a space (which is actually pointless, since you'll overwrite on the next non-space character), but not when you finish the loop, so if the input doesn't end with whitespace, the string isn't NUL-terminated.
You're advancing (or not) j correctly within the loop, but also advancing it in the for loop increment step, so you'll leave NULs scattered around (prematurely terminating the string) and skip non-space characters before then.
try this
void removeWS(char *strNoSpace, const char *strWithSpace)
{
int i, j;
strNoSpace = malloc(strlen(strWithSpace) + 1);
if ( strNoSpace == NULL ) {
// error handle
}
for(i = 0, j = 0; strWithSpace[i] != '\0'; i++ ) {
if ( isspace( strWithSpace[ i ] ) == 0 ) {
strNoSpace[j++] = strWithSpace[i];
}
}
strNoSpace[ j ] = '\0';
}

How can I make a function to remove double letters in C?

I am trying to make a function that removes double letters from a string. The function is only supposed to remove double letters next to each other, not in the whole string. e.g 'aabbaa' would become 'aba' (not 'ab'). Im a fairly new to c programming and dont fully understand pointers etc. and need some help. Below is what I have so far. It does not work at all, and I have no idea what to return since when I try and return string[] it has an error:
char doubleletter( char *string[] ) {
char surname[25];
int i;
for((i = 1) ; string[i] != '\0' ; i++) {
if (string[i] == string[(i-1)]) { //Supposed to compare the ith letter in array with one before
string[i] = '\0' ; //Supposed to swap duplicate chars with null
}
}
surname[25] = string;
return surname ;
Try the following. It is a clear simple and professionally-looked code.:)
#include <stdio.h>
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q ) *++p = *q;
}
return s;
}
int main(void)
{
char s[] = "aabbaa";
puts( unique( s ) );
return 0;
}
The output is
aba
Also the function can be rewritten the following way that to escape unnecassary copying.
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q )
{
( void )( ( ++p != q ) && ( *p = *q ) );
}
}
return s;
}
Or
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q && ++p != q ) *p = *q;
}
return s;
}
It seems that the last realization is the best.:)
First of all delete those parenthenses aroung i = 1 in for loop (why you put them there in the first place ?
Secondly if you put \0 in the middle of the string, the string will just get shorter.
\0 terminates array (string) in C so if you have:
ababaabababa
and you replace second 'a' in pair with \0:
ababa\0baba
effectively for compiler it will be like you just cut this string to:
ababa
Third error here is probably that you are passing two-dimensional array to function here:
char *string[]
This is equivalent to passing char **string and essentialy you are passing array of strings while you wanna only to pass a string (which means a pointer, which means an array: char *string or ofc char string[])
Next thing: you are making internal assumption that passed string will have less than 24 chars (+ \0) but you don't check it anywhere.
I guess easiest way (though maybe not the most clever) to remove duplicated chars is to copy in this for loop passed string to another one, omitting repeated characters.
One example, It does not modify input string and returns a new dynamically allocated string. Pretty self explanatory I think:
char *new_string_without_dups(const char *input_str, size_t len)
{
int i = 1;
int j = 0;
char tmpstr[len+1] = {0};
for (; i < len; i++) {
if (input_str[i] == input_str[i-1]) {
continue;
}
tmpstr[j] = input_str[i];
j++;
}
return strdup(tmpstr);
}
Don't forget to free the returned string after usage.
Note that there are several ways to adapt/improve this. One thing now is that it requires C99 std due to array size not being known at compile time. Other things like you can get rid of the len argument if you guarantee a \0 terminated string as input. I'll leave that as excercises.
Your idea behind the code is right, but you are making two fundamental mistakes:
You return a char [] from a function that has char as return type. char [], char * and char are three different types, even though in this case char [] and char * would behave identically. However you would have to return char * from your function to be able to return a string.
You return automatically allocated memory. In other languages where memory is reference counted this is OK. In C this causes undefined behavior. You cannot use automatic memory from within a function outside this very function. The memory is considered empty after the function exits and will be reused, i.e. your value will be overwritten. You have to either pass a buffer in, to hold the result, or do a dynamic allocation within the function with malloc(). Which one you do is a matter of style. You could also reuse the input buffer, but writing the function like that is undesirable in any case where you need to preserve the input, and it will make it impossible for you to pass const char* into the function i.e. you would not be able to do do something like this:
const char *str = "abbc";
... doubleletter(str,...);
If I had to write the function I would probably call it something like this:
int doubleletter (const char *in, size_t inlen, char *out, size_t outlen){
int i;
int j = 0;
if (!inlen) return 0;
if (!outlen) return -1;
out [j++] = in[0];
for (i = 1; i < inlen; ++i){
if (in[i - 1] != in[i]){
if (j > outlen - 1) return -1;
out[j++] = in[i];
}
}
out[j] = '\0';
return j - 1;
}
int main(void) {
const char *str1 = "aabbaa";
char out[25];
int ret = doubleletter(str1, strlen(str1), out, sizeof(out)/sizeof(out[0]));
printf("Result: %s", out);
return 0;
}
I would recommend using 2 indices to modify the string in-place:
void remove_doubles(char *str)
{
// if string is 1 or 0 length do nothing.
if(strlen(str)<=1)return;
int i=0; //index (new string)
int j=1; //index (original string)
// loop until end of string
while(str[j]!=0)
{
// as soon as we find a different letter,
// copy it to our new string and increase the index.
if(str[i]!=str[j])
{
i++;
str[i]=str[j];
}
// increase index on original/old string
j++;
}
// mark new end of string
str[i+1]='\0';
}

Reversing a string in C using pointers?

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;
}

Resources