Issues reverting a char array with C++ via pointers - c++

I am well aware that the instructions for this are highly innefficient/almost obsolete. I actually developed a much simpler solution using strings, but for education purposes, my university has decided to make it a requirement that we solve this issue by the use of pointers and char arrays rather than strings.
Basically, I need to pass a predefined char array (a specific phrase) and have it returned reversed.
So far, my output is absolute gibberish (Some characters which I cannot even type here) so I assume I must be doing something very wrong, but I can't see why.
To experiment, I tried to manually assign the *ptr_cha at the end of the function body to be something like "Hello", but then I'm met with type conversion errors. If I manually assign temp[0] to be "hello", and skip out the for cycle and simply say at the end that *ptr_cha[0] is equal to temp[0], I still get gibberish.
And if I try to output the contents of clone at the start of the function (after saying it's equal to ptr_cha[0]), it says the contents are "d", a letter which is not even present in the original sentence.
This is my whole code:
#include <iostream>
#include <wchar.h>
#include <locale.h>
#include <array>
using namespace std;
void invertChar(char *ptr_cha[]);
int main()
{
setlocale(LC_ALL, "");
char sentence[] {"Pablito clavó un clavito que clavito clavó Pablito"};
char *ptr_sentence[] {nullptr};
*ptr_sentence = sentence;
invertChar(ptr_sentence);
cout << ptr_sentence[0];
};
void invertChar(char *ptr_cha[]) {
char clone[] = {""};
char temp[] = {""};
ptr_cha[0] = clone;
int length = sizeof(clone)/sizeof(*clone);
int j = length;
for(int i = 0; i < length; i++) {
temp[i] = clone[j];
j--;
};
*ptr_cha[0] = temp[0];
};
As mentioned, the idea is for sentence to be set to its inverted form and displayed in the output.
As an additional, side question: Why is calculating the length of a char array in c++ so complicated/verbose? For strings there's a simple method, here you have to do this whole "trick" of dividing the sizeof the array by the sizeof its reference. I don't even see how the storage size of the array divided by the storage size of its pointer could return the length of the array...

Let me break down what's happening in each step. If you're using an IDE I highly recommend you to debug your program and see what's happening in each step. (In your code I assumed that you wanted to reverse 'sentence' and not return a copy of its reversed version.)
wchar.h and array are not used here, you can just delete those lines.
Other than that, you shouldn't pass a character string to a function like that. See this how to do properly.
#include <iostream>
#include <wchar.h> // Not used.
#include <locale.h>
#include <array> // Not used.
using namespace std;
void invertChar(char *ptr_cha[]);
Here, you should just pass sentence to invertChar, ptr_sentence is unnecessary and strange (char* ptr_sentence would be enough because now it's an array that contains pointers to chars and you store the address of sentence in its first slot).
int main()
{
setlocale(LC_ALL, "");
char sentence[] {"Pablito clavó un clavito que clavito clavó Pablito"};
char *ptr_sentence[] {nullptr};
*ptr_sentence = sentence;
invertChar(ptr_sentence);
cout << ptr_sentence[0];
};
void invertChar(char *ptr_cha[]) {
char clone[] = {""};
char temp[] = {""};
You are assigning clone to ptr_cha[0], now ptr_cha[0] is referencing clone and not to sentence. At this point you cannot reach sentence.
ptr_cha[0] = clone;
The first line below would be more descriptive written like this: int length = sizeof(clone) / sizeof(clone[0]). This divides the size of clone with the size of its first element, basically giving you the number of elements clone has. It's important to divide by the element size because what if clone uses something to store characters that isn't 1 byte long like char. You can get the number of elements of any array with this trick.
int length = sizeof(clone)/sizeof(*clone);
int j = length;
for(int i = 0; i < length; i++) {
Remember that both temp and clone are empty strings, more precisely they have 1 element and that's the \0 character that indicates the end of the string.
In the first run of the loop you are doing this: temp[0] = clone[1] but clone doesn't have a second element (index 1). At this point you are accessing something that's out of the array and assigning it to temp where it gets interpreted as a char, resulting in some "gibberish".
temp[i] = clone[j];
j--;
};
*ptr_cha[0] = temp[0];
};
Overall, I would recommend you to look into pointers and how they are working because they can be a little tricky and confusing.
Working C(++) implementation:
#include <iostream> // cout
#include <locale.h> // setlocale
#include <string.h> // strlen
void reverse(char* string)
{
// Check whether our pointer really points to something or not.
if (string == nullptr) return;
// 'strlen' returns the size of a '\0' terminated character sequence (including the '\0').
// We subtract 1 from the length because we don't want to swap the terminating
// '\0' character with the first one.
const int length = strlen(string) - 1;
for (int i = 0, j = length; i < j; ++i, --j) {
const char temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
int main()
{
setlocale(LC_ALL, "");
char sentence[] = "Pablito clavó un clavito que clavito clavó Pablito";
reverse(sentence);
std::cout << sentence << '\n';
return 0;
}
C++ implementation just for comparison:
#include <algorithm> // reverse
#include <iostream> // cout
#include <locale> // locale, locale::global
#include <string> // string
void reverse(std::string& string)
{
std::reverse(string.begin(), string.end());
}
int main()
{
std::locale::global(std::locale(""));
std::string sentence = "Pablito clavó un clavito que clavito clavó Pablito";
reverse(sentence);
std::cout << sentence << '\n';
return 0;
}

Related

How do I reverse a c string without the use of strlen?

I'm trying to implement a void function that takes a c string as its only parameter and reverses it and prints it. Below is my attempt at a solution however I'm not sure how to go about this problem.
void printBackwards(char forward[]) {
int i = 0;
char backwards[];
while (forward[i] != '\0') {
backwards[i] = forward[-i - 1];
i++;
}
cout << backwards;
}
Under such a condition, I guess you are expected to use recursion.
void printBackwards(char forward[]) {
if (!forward[0])
return;
printBackwards(forward + 1);
cout << forward[0];
}
Not being able to use strlen, we'll calculate it ourselves using a simple for loop. Then dynamically allocate a suitable buffer (add one character for the null terminating char, and I "cheated" by using calloc to zero the memory so I don't have to remember to set the null terminator. Then anoher simple loop to copy the original into the result in reverse.
#include <stdlib.h>
#include <stdio.h>
char *rev(char *s) {
size_t i;
char *s2 = s; // A pointer to the beginning as our first loop modifies s
for (i = 0; *s; s++, i++);
char *result = calloc(0, i + 1);
if (!result) return NULL; // In case calloc didn't allocate the requested memory.
for (size_t j = 0; j < i; j++)
result[j] = s2[i - j - 1];
return result;
}
Assuming you want to reverse the string rather than just printing it in reverse order, you first need to find the last character location (actually the position of the null terminator). Pseudo-code below (since this is an educational assignment):
define null_addr(pointer):
while character at pointer is not null terminator:
increment pointer
return pointer
Then you can use that inside a loop where you swap the two characters and move the pointers toward the center of the string. As soon as the pointers become equal or pass each other the string is reversed:
define reverse(left_pointer):
set right_pointer to null_addr(left_pointer)
while right_pointer > left_pointer plus one:
decrement right_pointer
swap character at left_pointer with character at right_pointer
increment left_pointer
Alternatively (and this appears to be the case since your attempt doesn't actually reverse the original string), if you need to print the string in reverse order without modifying it, you still find the last character. Then you run backwards through the string printing each character until you reach the first. That can be done with something like:
define print_reverse(pointer):
set right_pointer to null_addr(pointer)
while right_pointer > pointer:
decrement right_pointer
print character at right_pointer
That's probably better than creating a new string to hold the reverse of the original, and then printing that reverse.
One thing you should keep in mind. This very much appears to be a C-centric question, not a C++ one (it's using C strings rather than C++ strings, and uses C header files). If that's the case, you should probably avoid things like cout.
By using abstractions, like , your code will be much better at communication WHAT it is doing instead of HOW it is doing it.
#include <iostream>
#include <string>
#include <ranges>
int main()
{
std::string hello{ "!dlrow olleH" };
for (const char c : hello | std::views::reverse)
{
std::cout << c;
}
return 0;
}
Use a template
#include <iostream>
template<int N, int I=2>
void printBackwards(char (&forward)[N]) {
std::cout << forward[N-I];
if constexpr (I<N) printBackwards<N, I+1>(forward);
}
int main() {
char test[] = "elephant";
printBackwards(test);
}
While there seems to be several working answers, I thought I'd throw my hat in the stack (pun intended) since none of them take advantage of a FILO data structure (except #273K's answer, which uses a stack implicitly instead of explicitly).
What I would do is simply push everything onto a stack and then print the stack:
#include <stack>
#include <iostream>
void printBackwards(char forward[]) {
// Create a stack to hold our reversed string
std::stack<char> stk;
// Iterate through the string until we hit the null terminator
int i = 0;
while (forward[i] != '\0'){
stk.push(forward[i]);
++i;
}
// Iterate through the stack and print each character as we pop() it
while (stk.size() > 0){
std::cout << stk.top();
stk.pop();
}
// Don't forget the newline (assuming output lines should be separated)
std::cout << '\n';
}
int main(int argc, char* argv[]){
char s[] = "This is a string";
printBackwards(s);
return 0;
}
Hi guys as promised I have come back to add my own answer. This is my own way using array subscripts and using what I currently know.
#include <iostream>
using namespace std;
void printBackwards(char[]);
int main()
{
char word[] = "apples";
printBackwards(word);
return 0;
}
void printBackwards(char word[]) {
char* temp = word;
int count = 0;
while (*temp++ != '\0') {
count++;
}
for (int i = count - 1; i >= 0; i--) {
cout << word[i];
}
}
You can make a fixed-size buffer and create new ones if needed. Fill it reverse by moving the string offset back with every inserted character. Chars exceeding the buffer are returned to be processed later, so you can make a list of such buffers:
template<int SIZE>
struct ReversedCStr
{
static_assert(SIZE > 10); // just some minimal size treshold
// constexpr
ReversedCStr(char const* c_str, char const** tail = nullptr) noexcept
{
for(buffer[offset] = '\0'; *c_str != '\0';)
{
buffer[--offset] = *c_str++;
if(offset == 0) break;
}
if(tail) *tail = c_str;
}
//constexpr
char const* c_str() const noexcept { return buffer.data()+offset;};
private:
size_t offset = SIZE -1;
std::array<char,SIZE> buffer;
};
The tag is 'C++' so I assume you use C++ not C. The following code is C++11 so it should fit in every modern project. I posted the working example on godbolt.org.
It doesn't allocate memory, and is completely exception-free. The maximum memory wasted is {buffer_size + sizeof(char*)*number_of_chunks}, and can be easily turned into a list of reversed chunks like this:
char const* tail;
std::vector<ReversedCStr<11>> vec;
for(vec.emplace_back(str,&tail); *tail != '\0';)
vec.emplace_back(tail,&tail);

C++ - How do I frequency count characters?

I need to write code to store the unique characters and their frequencies in a dynamic array. I need to increase its size as new data comes in. New data in this case will be a new character that is encountered. The algorithm I have in mind is to check the list of known characters every single time I read from the given string. If it is a new character I need to increase the array size by 1. If it is not a new character I will increase its frequency. It is an array of struct letter (in the code below). The problem is that, I spent quite a lot of time with this and had issues with implementing it. So the question is how can I exactly implement it? Thank you spending time to help.
#include <iostream>
#include <string>
#include <bitset>
#define ARR_LEN(arr) sizeof(arr)/sizeof(arr[0])
using namespace std;
struct unique_char {
char character;
int frequency;
};
int main() {
int char_count;
string str;
getline(cin, str);
struct unique_char* chars = new struct unique_char[100];
system("PAUSE");
exit(0);
}
As mentionned in the comments, using std::map makes this fairly straightforward.
One of the "fun" things about map is that the indexing operator creates new values "on demand" with a initial value of 0 for ints. So the actual code is essentially one line: chars[c] += 1;
#include <map>
#include <iostream>
#include <string>
using namespace std;
int main() {
map<char, int> chars;
string str;
getline(cin, str);
for(char c: str) {
chars[c] += 1;
}
for(auto [character, frequency]: chars) {
cout << character << " : " << frequency << "\n";
}
}
N.B. There is one major difference between this and #ThomasMatthews's answer:
The map will only contain the characters that have been seen, whereas the array will contain 0s for all characters that were never hit. Which approach you use should be based on which of the two are more useful to you.
Using an array makes things straight forward:
unsigned int frequencies[256] = {0};
while (std::getline(std::cin, str))
{
const size_t length = str.length();
for (unsigned int i = 0; i < length; ++i)
{
const char c = str[i];
++frequencies[c];
}
}
Although, you may want to improve efficiency:
const size_t BUFFER_SIZE = 1024u * 1024u;
//...
char buffer[BUFFER_SIZE] = {0};
while (std::cin.read(&buffer[0], BUFFER_SIZE)
{
const size_t chars_read = cin.gcount();
for (unsigned int i = 0; i < chars_read; ++i)
{
const char c = buffer[i];
++frequencies[c];
}
}
The above code uses block reading to improve input performance. No scanning for newline characters, just read straight into memory. Determine the frequencies from the characters in memory.
Edit 1: unsigned char
From the comments, an unsigned char may be a safer data type than char because char can be signed. This may be an issue when accessing the array slots because a signed char could be negative and negative indices are usually a bad thing. When you run it, if there are issues, replace the char type with unsigned char.

Array of char arrays C++

I am writing an exchange program and I have a char array that holds another 6 char arrays. The program works fine except for one thing: when I try to print the arrays' values, it prints only the first letter.
Maybe the code isn't right, but I didn't find another way to make this exchange. Actually I think the problem is in pointers that point to that arrays, but again I am not sure.
Here is the code:
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
using namespace std;
int main(int argc, char* argv[])
{
cout<<"EXCHANGE POKEMON:"<<endl;
char a[100]="PIKACHU", b[100]="CHARMELEON", c[100]="GEODUDE", d[100]="GYARADOS", e[100]="BUTTERFREE", f[100]="MANKEY", tmp[100];
char t[6] = {*a,*b,*c,*d,*e,*f};
while(1)
{
for(int i = 0; i < 6; i++)
{
cout << i << ") " << t[i] <<endl;
}
cout<<endl<<"Choose a pokemon:";
int x, y;
cin>>x;
if(x == -1)
{
exit(0);
}
cout << "Choose a pokemon to exchange with:";
cin>>y;
*tmp = t[x];
t[x] = t[y];
t[y] = *tmp;
}
}
With this line:
char t[6];
you are not creating an array of arrays of char. You are creating a simple array of chars. So it is no surprise that every element is a single character.
You probably want:
char *t[6] = {a, b, c, d, e, f};
Note that the *a is actually equivalent to a[0]!
Then the tmp array is used wrong: in C you copy strings with strcpy(), not with the assignment operator. Or alternatively you hold a pointer to the original string.
But you are using C++, so why not just use std::string? Maybe you are just learning arrays and want to do it the hard way?
You defined t as an array of char, initialized dereferencing the address of the arrays defined before. That is equivalent to obtaining their first element.
*a is equivalent to a[0]
What you are looking for is an array of char pointer instead:
char *t[6] = {a,b,c,d,e,f};

Converting from int to CString

TestString::TestString(int num)
This is a conversion constructor that should convert an integer to a string.
For example, if 123 is passed in, the TestString object should store the string data that would be represented by the c-string "123".
class TestString //header file
{
public:
TestString (int num);
//etc.
private:
int size;
char* str;
};
TestString::TestString (int num) //.cpp file
{
char c = static_cast<char>(num);
str = new char[size]; //missing size variable
int i = 0;
for (i; cstr[i] != '\0'; i++) //missing cstr array
str[i] = cstr[i];
str[i] = cstr[i]; //to tack on null character
}
As you can tell I am missing both the size variable and cstr string in the definition. I don't know if I'm going about this all wrong or just having trouble understanding what sort of setup I'm being asked for...
Any pointers or suggestions greatly appreciated.
Only libraries permitted:
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cctype>
So by what I understand you want to get the length required for the output string. I guess the only way to do that without <cmath> is using a while loop as such:
int len=0;
int num2=num;
do{
num2=num2/10;
len++;
} while (num2>0);
which basically keeps dividing the number by 10 to get how many digits it has.
Then, for each character you can do this: Say you want the character for 0, just use '0'. If you want the character for '1', use '0'+1 which will return 1.
If you need any more help (a full implementation), just comment below and I'll get to you. Have fun!
you don't need any other things than pure vanilla C++ , just use std::to_string:
std::string ouputString = std::to_string(inputInteger);
now you can pull out C-string with std::string::c_str:
ouputString.c_str()

Reversing a string, weird output c++

Okay, so I'm trying to reverse a C style string in C++ , and I'm coming upon some weird output. Perhaps someone can shed some light?
Here is my code:
int main(){
char str[] = "string";
int strSize = sizeof(str)/sizeof(char);
char str2[strSize];
int n = strSize-1;
int i =0;
while (&str+n >= &str){
str2[i] = *(str+n);
n--;
i++;
}
int str2size = sizeof(str)/sizeof(char);
int x;
for(x=0;x<str2size;x++){
cout << str2[x];
}
}
The basic idea here is just making a pointer point to the end of the string, and then reading it in backwards into a new array using pointer arithmetic.
In this particular case, I get an output of: " gnirts"
There is an annoying space at the beginning of any output which I'm assuming is the null character? But when I try to get rid of it by decrementing the strSize variable to exclude it, I end up with some other character on the opposite end of the string probably from another memory block.
Any ideas on how to avoid this? PS: (would you guys consider this a good idea of reversing a string?)
A valid string should be terminated by a null character. So you need to keep the null character in its original position (at the end of the string) and only reverse the non-null characters. So you would have something like this:
str2[strSize - 1] = str[strSize - 1]; // Copy the null at the end of the string
int n = strSize - 2; // Start from the penultimate character
There is an algorithm in the Standard Library to reverse a sequence. Why reinvent the wheel?
#include <algorithm>
#include <cstring>
#include <iostream>
int main()
{
char str[] = "string";
std::reverse(str, str + strlen(str)); // use the Standard Library
std::cout << str << '\n';
}
#ildjarn and #Blastfurnace have already given good ideas, but I think I'd take it a step further and use the iterators to construct the reversed string:
std::string input("string");
std::string reversed(input.rbegin(), input.rend());
std::cout << reversed;
I would let the C++ standard library do more of the work...
#include <cstddef>
#include <algorithm>
#include <iterator>
#include <iostream>
int main()
{
typedef std::reverse_iterator<char const*> riter_t;
char const str[] = "string";
std::size_t const strSize = sizeof(str);
char str2[strSize] = { };
std::copy(riter_t(str + strSize - 1), riter_t(str), str2);
std::cout << str2 << '\n';
}
while (&str+n >= &str){
This is nonsense, you want simply
while (n >= 0) {
and
str2[i] = *(str+n);
should be the much more readable
str2[i] = str[n];
Your while loop condition (&str+n >= &str) is equivalent to (n >= 0).
Your *(str+n) is equivalent to str[n] and I prefer the latter.
As HappyPixel said, your should start n at strSize-2, so the first character copied will be the last actual character of str, not the null termination character of str.
Then after you have copied all the regular characters in the loop, you need to add a null termination character at the end of the str2 using str2[strSize-1] = 0;.
Here is fixed, working code that outputs "gnirts":
#include <iostream>
using namespace std;
int main(int argc, char **argv){
char str[] = "string";
int strSize = sizeof(str)/sizeof(char);
char str2[strSize];
int n = strSize-2; // Start at last non-null character
int i = 0;
while (n >= 0){
str2[i] = str[n];
n--;
i++;
}
str2[strSize-1] = 0; // Add the null terminator.
int str2size = sizeof(str)/sizeof(char);
int x;
cout << str2;
}