0

I need to know how char * functions works and how we can manipulate char * array in a function and return it. Take help of following code for explanations and why it is not printing anything?? And I can't use std::string. It was a function based question in which i could not use std::string. and had to return ans from function

#include<stdio.h>
using namespace std;
char * change(char *str)
{
    char *s="S";
    for(int i=1;str[i]!='\0';i++)
    {
        s[i]=str[i]+32;
    }
    return s;
}
int main()
{
    char  *str="SampleRun";
    cout<<change(str);
}
Sachin
  • 70
  • 11
  • 2
    Your code invokes *undefined behavior* and your compiler should warn you about `char *str="SampleRun";` - a string literal is not mutable – UnholySheep Apr 12 '19 at 21:42
  • 3
    There are a lot of things wrong in your code here. First, `'\0'` is a null character, `'/0'` is (if not a compilation error) a forward slash. Second, arrays are 0 indexed, so your loop should initialize `i` to 0. Third, you have initialized `s` to a static character array with two elements, and `s[i]` is sure to write past the end of the the array (ignoring the fact that the array contents should be constant as well). Also, you are returning `s`, whose memory exists on the stack frame for `change` and will be destroyed after exiting the function. Using it after this is very bad. – cyberbisson Apr 12 '19 at 21:43
  • @cyberbisson if it is static then how to convert str into uppercase and return it from function?? – Sachin Apr 12 '19 at 21:57
  • 2
    @cyberbisson `'/0'` is a multicharacter literal. – eerorika Apr 12 '19 at 21:58
  • 1
    Your best bet is to use `std::string` instead of messing around with raw `char*`s. – Miles Budnek Apr 12 '19 at 21:59
  • 1
    Unrelated: prefer `s[i]=str[i]+' ';` to `s[i]=str[i]+32;`. It is easier to infer the intent of `' '` than `32` and space need not always be 32. In general, [What is a magic number, and why is it bad?](https://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad) – user4581301 Apr 12 '19 at 22:00
  • Guys, I can't use std::string. It was a function based question in which i could not use std::string. and had to return ans from function. – Sachin Apr 12 '19 at 22:01
  • 2
    That's good information to put in the question. – user4581301 Apr 12 '19 at 22:03
  • @eerorika I do know it's a literal for the record -- actually we used these for IDs back when I worked at Palm. :). Certainly, though, it's not the string terminator he was looking for. As an aside, I should mention that the memory returned from this function will not be descoped, like I claimed initially, as it's just pointing to the static area, but that point is a little fine for the question that's being asked. – cyberbisson Apr 13 '19 at 00:27

1 Answers1

3

The code you have shown will not work as-is, as it has a lot of mistakes and undefined behavior in it.

  • using std::cout without #include <iostream>

  • using <stdio.h> instead of <cstdio>

  • in change(), pointing s to read-only memory (illegal in C++11 and later!), looping using an invalid loop counter, and trying to copy more characters from str to s than are allocated to s.

  • in main(), pointing str to read-only memory.

You need to use something more like this instead:

#include <iostream>
#include <cstring>
using namespace std;

char* change(char *str)
{
    int len = strlen(str);
    char *s = new char[len + 1];
    for(int i = 0; i < len; ++i)
    {
        s[i] = str[i] + 32;
    }
    s[len] = '\0';
    return s;
}

int main()
{
    char *str = change("SampleRun");
    cout << str;
    delete[] str;
    return 0;
}

Or this:

#include <iostream>
#include <cstring>
using namespace std;

char* change(char *str, int len)
{
    for(int i = 0; i < len; ++i)
    {
        str[i] += 32;
    }
    return str;
}

int main()
{
    char str[] = "SampleRun";
    cout << change(str, strlen(str));
    return 0;
}

But, since you are using C++, you really should be using std::string instead:

#include <iostream>
#include <string>
using namespace std;

string change(const string &str)
{
    string s;
    s.reserve(str.length());
    for(char ch : str)
    {
        s.push_back(ch + 32);
    }
    return s;
}

int main()
{
    cout << change("SampleRun");
    return 0;
}

Or this:

#include <iostream>
#include <string>
using namespace std;

void change(string &str)
{
    for(char &ch : str)
    {
        ch += 32;
    }
}

int main()
{
    string str = "SampleRun";
    change(str);
    cout << str;
    return 0;
}

That being said, if your goal is to lowercase a string (the only sensible reason to add 32 to characters, unless you are trying to implement obscurity via a basic rotation cipher), then rather than blindly adding 32 to every character, consider using std::tolower() instead. You can use that with std::transform(), for instance. This is a common (albeit not an entirely accurate) way to lowercase strings in C++, eg:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

char* change(char *str)
{
    int len = strlen(str);
    char *s = new char[len + 1];
    transform(str, str+len, s, [](unsigned char ch){ return tolower(ch); });
    s[len] = '\0';
    return s;
}

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

char* change(char *str, int len)
{
    transform(str, str+len, str, [](unsigned char ch){ return tolower(ch); });
}

#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;

string change(const string &str)
{
    string s;
    s.reserve(str.length()); 
    transform(str.begin(), str.end(), back_inserter(s), [](unsigned char ch){ return tolower(ch); });
    return s;
}

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

void change(string &str)
{
    transform(str.begin(), str.end(), str.begin(), [](unsigned char ch){ return tolower(ch); });
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770