5

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!

Cmag
  • 14,946
  • 25
  • 89
  • 140
  • What is the type of `base64output`? – Tony The Lion May 15 '13 at 19:15
  • 4
    This won't work. You're trying to fit 3 characters into a single 'char', which is UB. – Richard J. Ross III May 15 '13 at 19:27
  • @RichardJ.RossIII i see that! how should i write this then? – Cmag May 15 '13 at 19:30
  • 2
    Actually "+", "/", "=" are all `const char *`. As pointed out by RichardJ.RossIII '%2B' is not a character and maybe you need to pass it as *string* "%2B". So maybe your function should take in `char *, const char *, const char*`. Also you have to make sure that your target string has enough memory to accommodate replacement – another.anon.coward May 15 '13 at 19:36
  • is this how i would write this?char replace_char (char *, const char*, const char*) { – Cmag May 15 '13 at 19:40
  • 3
    No, it is just a suggestion, you can actually pass +, /, = as character '+', '/', '='. Maybe use `char* replace(char *, const char, const char*)` . What I am saying is that you should make sure that `signature` is large enough to accommodate change for eg, if signature="hello+test" after change it will be "hello%2Btest" which is 2 more chars than before. So your function logic can a) assume that input string has enough memory allocated or b) takes care of this memory allocation. It is up to you to decide – another.anon.coward May 15 '13 at 19:46
  • s.c:266: warning: initialization makes pointer from integer without a cast – Cmag May 15 '13 at 19:50
  • i need to be returning something back from the function, what should it be? – Cmag May 15 '13 at 20:00
  • updated the code, still nothing – Cmag May 15 '13 at 20:11
  • / is not a valid C char? – Cmag May 15 '13 at 21:10

6 Answers6

6

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

yoones
  • 2,394
  • 1
  • 16
  • 20
  • Not only that, you also use strings (char*) as parameters when the method expects characters (char). – Dirk May 15 '13 at 19:46
  • s.c:266: warning: initialization makes pointer from integer without a cast – Cmag May 15 '13 at 19:50
3

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);
}
asveikau
  • 39,039
  • 2
  • 53
  • 68
  • @Clustermagnet - 1. It returns `int` which is `0` on success, nonzero on error. As you learn C more you will see this is a common pattern. 2. I'm going to guess you pasted this into somewhere where `replace` was already defined. – asveikau May 16 '13 at 01:09
3

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.

Community
  • 1
  • 1
Joe DF
  • 5,438
  • 6
  • 41
  • 63
1

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..

stdcall
  • 27,613
  • 18
  • 81
  • 125
1

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;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • 1
    This solution assumes the source has enough space. – asveikau May 16 '13 at 02:53
  • 1
    @asveikau That's correct. It has been assumed in the original code. – BLUEPIXY May 16 '13 at 07:51
  • awesome! thanks! Now, question, what if i needed to increase the base64output variable, since im replacing single characters with tripple characters – Cmag May 16 '13 at 14:52
  • Change it to use the area secured by the securing region using the malloc, etc. If it appears that the output region is lacking. Do you would prepare three times maximum number of characters that are assumed in the input, and then calculate the required area by counting the number of blank if you want to reserve in advance. – BLUEPIXY May 16 '13 at 15:08
  • The reason I point it out is that it's not a good habit to teach people that they can write C code disregarding buffer sizes. – asveikau May 17 '13 at 05:36
  • If it has not been a particular problem that I can not bring myself to point out each time a matter of course. – BLUEPIXY May 17 '13 at 08:36
  • You and all the others who don't think they have to think about buffer sizes, who come up with broken interfaces like `gets()` and `strcpy()` and exploitable buffer overflows etc.. Good C programming in the 21st century *demands* that you constantly be aware of buffer sizes; people learning the language should be steered into disciplined usage and sane patterns. – asveikau May 17 '13 at 18:06
  • It depends on what is required in the program. It's trying to make a cup that does not full of absolutely and provisions drums when I want a glass of water it is ridiculous. Tentatively, It is well enough without your teaching. – BLUEPIXY May 17 '13 at 18:12
  • E.g. What guard also does not exist strcpy, strncpy. Just because I don't think even wants to ensure the memory automatically. May be also such a function if you need. – BLUEPIXY May 17 '13 at 18:36
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;
}