Hello to all. I have a problem with replacing a part of a string with another string.
The following code does not work. However, if you remove void in front of replace_str, in Code Blocks i am able to run it (WHY???) despite the fact that i still get a warning:

"argument 1 of 'puts' makes pointer from integer without a cast"

Also, this "program" only replaces the first occurance of s2 in s1 and it should replace all.

Plus, i would like to know the correct sintax to print res using printf (the comment in code does not do it).

Every part of code besides

void replace_str(char *res, char *str, char *orig, char *rep)

can be changed (according to assingment).

Any sort of help would be much appreciated.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define SIZE 1024

void replace_str(char *res, char *str, char *orig, char *rep)
{
   char buffer[4096];
  int i;
  char *p;

  if(!(p=strstr(str, orig))){
    for(i=*p;i<strlen(orig);i++)
    res[i]=str[i];
  }
  else{
  strncpy(buffer, str, p-str);
  buffer[p-str] = '\0';

  sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));

  res=buffer;
}}

main()
{char res[SIZE],s1[SIZE],s2[SIZE],s3[SIZE];
scanf(" %s",s1);
scanf(" %s",s2);
scanf(" %s",s3);
 puts(replace_str(res,s1, s2, s3));
  //replace_str(res,s1, s2, s3);
//printf(" %s\n",res);
  return 0;
}

The following code does not work.

Obviously. You're trying to print the return value of a function that returns void.

However, if you remove void in front of replace_str, in Code Blocks i am able to run it (WHY???) despite the fact that i still get a warning

Prior to C99, omitting the return type from a function causes the compiler to assume that you meant int. This is the implicit int rule, and the two following declarations are equivalent:

replace_str(char *res, char *str, char *orig, char *rep);
int replace_str(char *res, char *str, char *orig, char *rep);

It's not wise to rely on this rule though, as mentioned, it no longer exists in the latest revision of the C language.

Plus, i would like to know the correct sintax to print res using printf (the comment in code does not do it).

The bigger problem is that you're pointing res in replace_str() to a different place, not copying the contents of buffer into res . The code should be more like this (for replacing the first occurrence:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define SIZE 1024

char *replace_str(char *res, char *str, char *orig, char *rep)
{
    char buffer[4096];
    int i;
    char *p;

    if (!(p=strstr(str, orig))) {
        for(i=*p; i<strlen(orig); i++)
            res[i]=str[i];
    } else {
        strncpy(buffer, str, p-str);
        buffer[p-str] = '\0';
        sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
        strcpy(res, buffer); /* Still unsafe... */
    }
    
    return res;
}

int main(void)
{
    char res[SIZE],s1[SIZE],s2[SIZE],s3[SIZE];
    
    scanf(" %s",s1);
    scanf(" %s",s2);
    scanf(" %s",s3);
    puts(replace_str(res, s1, s2, s3));
    
    return 0;
}

Also, this "program" only replaces the first occurance of s2 in s1 and it should replace all.

Well, you only call strstr() once, so that's perfectly understandable. You have the right concept, it's just a matter of devising an algorithm for choosing whether to copy the original string vs. the replacement string:

char *replace_str(char *res, char *str, char *orig, char *rep)
{
    size_t orig_len = strlen(orig);
    size_t rep_len = strlen(rep);
    char *dst = res;
    
    while (*str != '\0') {
        if (strncmp(str, orig, orig_len) != 0)
            *dst++ = *str++;
        else {
            strncpy(dst, rep, rep_len);
            str += orig_len;
            dst += rep_len;
        }
    }
    
    *dst = '\0';
    
    return res;
}

Wow, man, you are good. Can you tell me why use size_t and not int for orig_len and rep_len? I tried it and it works with int as well. And what would i need to do so that the program would do the same if return type for function replace_str were void and not char?

Edited 5 Years Ago by The 42nd: n/a

Can you tell me why use size_t and not int for orig_len and rep_len?

Using size_t instead of just plain int or unsigned int makes your code more portable since the size of int types vary across platforms.
Also the above standard functions expect their third argument to be of size_t type.

char *stpncpy(char *restrict s1, const char *restrict s2, size_t n);
int strncmp(const char *s1, const char *s2, size_t n);

Can you tell me why use size_t and not int for orig_len and rep_len?

strlen() returns a value of type size_t. I like to use size_t for array sizing and indexing simply because it's a slightly better fit than int, and the standard library uses size_t extensively for that purpose.

Note that size_t is an unsigned type while int is signed, which has potential for subtle bugs if you mix them.

And what would i need to do so that the program would do the same if return type for function replace_str were void and not char?

You don't need to do anything, really. res is being passed as an argument, so it will be updated in the caller. Just modify the function a smidge to simplify things and you're done:

#include <stdio.h>
#include <string.h>

void replace_str(char *res, char *str, char *orig, char *rep)
{
    size_t orig_len = strlen(orig);
    size_t rep_len = strlen(rep);
 
    while (*str != '\0') {
        if (strncmp(str, orig, orig_len) != 0)
            *res++ = *str++;
        else {
            strncpy(res, rep, rep_len);
            str += orig_len;
            res += rep_len;
        }
    }
 
    *res = '\0';
}

int main(void)
{
    char res[BUFSIZ];
 
    replace_str(res, "thisisatest", "i", "foo");
    puts(res);
 
    return 0;
}

However, it is conventional to return a pointer to the beginning of the destination string rather than void in cases like this.

This question has already been answered. Start a new discussion instead.