How to solve this problem trying to iterate a string? - c++

I'm trying to invert the case of some strings, and I did it, but I have some extra characters in my return, is it a memory problem? Or because of the length?
char* invertirCase(char* str){
int size = 0;
char* iterator = str;
while (*iterator != '\0') {
size++;
iterator++;
}
char* retorno = new char[size];
for (int i = 0; i < size; i++) {
//if capital letter:
if (str[i] < 96 && str[i] > 64) {
retorno[i] = str[i] + 32;
}
// if lower case:
else if (str[i] > 96 && str[i] < 123) {
retorno[i] = str[i] - 32;
}
//if its not a letter
else {
retorno[i] = str[i];
}
}
return retorno;
}
For example, if I try to use this function with the value "Write in C" it should return "wRITE IN c", but instead it returns "wRITE IN cýýýýÝݱ7ŽÓÝ" and I don't understand where those extra characters are coming from.
PS: I know I could use a length function, but this is from school, so I can't do that in this case.

add +1 to the size of the char array.
char* retorno = new char[size+1];
add a null-terminated string before returning retorno.
retorno[size] = '\0';

Your output string is not null-terminated
When you iterate through the input string, you increment size until you reach null. That means the null is not copied to the output string. After you exit the loop, you should increment size once more to capture the end.
As an aside, it's probably a good idea to constrain size to some maximum (while(*iterator != '\0' && size < MAXSIZE)) in case someone passes a non-terminated string into your function. If you hit the max size condition, you'd need to explicitly add the null at the end of your output.

Your string should be null terminated; which is what you are looking for when you get the initial size of the string. When you create the new string, you should allocated size+1 chars of space, then retorno[size] should be set to a null terminating character (i.e. '\0'). When you attempt to print a char* using printf or cout (or similar mechanisms), it will keep printing characters until it find the null terminating character, which is why you are getting the garbage values after your expected output.
On another note, c++ has helpful functions like std::islower / std::isupper and std::tolower / std::toupper

From what I can tell, there could be 2 things going on here:
Like everyone here mentioned, the absence of a null terminating character ('\0') at the end of your char array could be causing this.
It could be the way you are printing results of your retorno character string outside of your invertirCase() function.
I tested out your function in C++14, C++17 and C++20 and it returned the correct result each time, both with the null terminating character at the end of the retorno char array and without it.
Try printing your result inside of your function before returning it, to identify if this is being caused inside of your function or outside of it. Like so:
char* invertirCase(char* str){
// [... truncated code here]
for (int i = 0; i < size; i++) {
// [... truncated code here]
}
cout << " **** TESTING INSIDE FUNCTION ****" << endl;
cout << "-- Testing index iteration" << endl;
for (int i = 0; i < size; i++) {
cout << retorno[i];
}
cout << endl;
cout << "-- Testing iterator iteration" << endl;
for (char* iterator = retorno; *iterator != '\0'; iterator++) {
cout << *iterator;
}
cout << endl;
cout << "-- Testing advanced for loop" << endl;
for (char character : retorno) {
cout << character;
}
cout << " **** END TESTING ****" << endl;
cout << endl;
return retorno;
}
This way you could possibly identify both if the problem occurs inside of your function or if the problem is occurring because of the way you may be printing your result as well.

Related

How to check if a character matches another character in a char array?

I'm currently trying to figure out how I can replace a certain character in a char array using a for loop to check each index position in the array. However, when I assign the correct character to the char variable "letterGuessed" and it is checked it instantly goes to the else statement. This leaves the character as an asterisks. This is the code below:
#include <iostream>
#include <cstring>
void hide_Word(char hide[], int size);
int main()
{
char hiddenWord[] = "Hello";
char displayWord[30] = { 0 };
int length = strlen(hiddenWord);
hide_Word(displayWord, length);
std::cout << hiddenWord << std::endl;
std::cout << displayWord << std::endl;
char letterGuessed;
std::cout << "Enter a character: ";
std::cin >> letterGuessed;
for (int i = 0; i < length; i++)
{
if (displayWord[i] == letterGuessed)
{
letterGuessed == displayWord[i];
}
else
{
std::cout << "*";
}
}
std::cout << std::endl;
std::cout << displayWord << std::endl;
std::cin.get();
return 0;
}
void hide_Word(char hide[], int size)
{
for (int i = 0; i < size; i++)
{
hide[i] = '*';
}
}
When I compile your code I get the warning
main.cpp|27|warning: statement has no effect [-Wunused-value]
for the line
letterGuessed == displayWord[i];
This, for one, means that what you do to make correctly guessed letters visible is achieving nothing. Reading and considering warning messages is really helpful, you know.
I guess that your goal here is to turn the "*", which you filled displayWord with, should be replaced by the correctly guessed character.
That would better be achieved by an assignment using =.
letterGuessed = displayWord[i]; /* still unhelpful */
But that line would still not achieve anything visible.
To change something in the displayWord, it should be what gets the guessed character as a new value, not the other way around.
displayWord[i] = letterGuessed;
This is however still not satisfying, because you don't do this in the right situation.
Let's have a look at the condition which determines when you do it.
if (displayWord[i] == letterGuessed) /* unhelpful */
This will trigger, when the guessed character is an asterisk "*", because displayWord is filled with asterisks early on.
Which means that the condition only triggers if the user guesses an asterisk, which is unlikely. Even if it happens, the result is to overwrite an asterisk with an asterisk.
The condition you need should not check the asterisk-filled displayWord, it should instead check the "Hello"-filled hiddenWord.
if (hiddenWord[i] == letterGuessed)
In total, the code should hence be
for (int i = 0; i < length; i++)
{
if (hiddenWord[i] == letterGuessed)
{
displayWord[i]=letterGuessed;
std::cout << letterGuessed;
}
else
{
std::cout << "*";
}
}
This turns an asterisk in the displayed word into the correctly guessed character at each found position.
Note that I added an output of the guessed letter, to complete the letter-by-letter output. I guess you want to delete that output, or the word-output after the loop, so that the filled in word is only seen once.
Output:
Hello
*****
Enter a character: l
**ll*
**ll*

I am trying to count the contents in a char array till the null-termination, but each time I compile i get a number larger than my array

No matter what value I set for the size of my array, the function I wrote returns a value some degree larger.
I've tried, while(*str++) and removing the str++ from inside the while loop, instead of what is there now.
I am using Visual Studio 2019.
int strlen(char* str)
{
int i = 0;
while (*str != '\0')
{
i++;
str++;
}
return i;
}
int main()
{
char line[1];
char* v = line;
char* s = new char[1];
cout << "for s " << strlen(s) << endl;
cout << "for v " << strlen(v) << endl;
}
You are neglecting to null-terminate your strings. Your function is iterating past the end of the array and causing Undefined Behavior. Some string-manipulation functions will put the null at the end, but if you want your string to have a terminal null, you must put it there yourself.
char line[2];
char* v = line;
line[0]='x';
line[1]= '\0';
The contents of your arrays are undefined. You are not filling any of the arrays with any characters, let alone with any null terminators. It is undefined behavior to call strlen() on a character array that is not properly null terminated.

The Program gives garbage value for name[i], i= 1 to 3

I am a beginner to programming. I was building a program to read in a single string, store it in different arrays and print them. But the output gives garbage values for name[0] and name[1] but the correct values for name[2] and name[3]. Any idea?
char buffer[80];
cin.getline(buffer, 80, '$');
char* name[4];
name[0] = buffer;
int count = 0;
for (char* p = buffer; *p != '\0'; p++)
if (*p == '\n') {
*p = '\0';
name[++count] = p+1;
}
cout << " Your Enteries are :" << '\n';
for (int i = 0; i < count; i++)
cout << '\t' << i << ". [" << name[i] << "] " << endl;
You're experiencing a buffer overflow for the array name.
Whan happens if you have (as I expect you do) 4 \n in your input? You execute the code inside the if (*p == '\n') branch 4 times. What is the value of the ++count expression? The first time since count is initialised to 0, ++count evaluates to 1, the second time it evaluates to 2, the third to 3, the fourth to 4. And what does that expression become when you substitute 4 to it?
name[4] = p+1;
So you're writing outside of the name array bounds, and destroy other variables in the stack in the process, in your case the start of the buffer array. If you are on a 64bit process you should expect 8 bytes of garbage at the beginning of buffer, which in your case happens to be where name[0] and name[1] point to.
This is always a risk when you're accepting input from user.
A solution in your case would be simply to bound check the arrays before accessing them:
for (char* p = buffer; *p != '\0'; p++)
if (*p == '\n') {
*p = '\0';
if (++count < 4) {
name[count] = p+1;
}
}

Putting Data From File To Char Array Doesn't Stop At Last Data

I'm rusty on using classes and am brushing up on using them. I've encountered a problem where I'm attempting to use a simple program to retrieve data from a file that holds a simple number ("1234" in this case).
#include <iostream>
#include <fstream>
class hold
{
public:
void enter();
hold();
private:
char x[50];
};
hold::hold()
{
x[50] = NULL;
}
void hold::enter()
{
std::ifstream inFile;
inFile.open("num.txt");
int pos = 0;
while(inFile.good())
{
inFile >> x[pos];
pos++;
}
std::cout << "strlen(x) = " << strlen(x) << std::endl;
for(int i = 0; i < strlen(x); i++)
{
std::cout << x[i] << " ";
}
std::cout << std::endl;
}
int main()
{
hold h;
h.enter();
system("pause");
return 0;
}
The output is:
strlen(x) = 50;
1 2 3 4 (following a bunch of signs I do not know how to print).
It's been almost a year since I've consistently practiced classes and I don't recall having used a character array in a class. Can anyone tell me where I'm messing up with this file not terminating after "4"? I've tried using if statements to break the while loop if "x[pos] == '\0', but it didn't work either.
You did not terminate your string and you have undefined behaviour because strlen is hitting elements of the array that were never initialised. Try this:
while( pos < 49 && inFile >> x[pos] )
{
pos++;
}
x[pos] = '\0';
Note that pos after the loop will now be the same as what is returned by strlen(x).
If you don't need a null-terminated string, then just use pos instead of strlen(x) without terminating but in that case you will need to avoid using any string functions that rely on null-terminated strings.
You also have a stack-smashing problem (undefined behaviour) in your constructor:
hold::hold()
{
x[50] = NULL;
}
This is not okay. You are not allowed to modify memory past the end of the array. If you want to zero it, you can just do
memset( x, 0, sizeof(x) );
Or in C++11:
hold::hold()
: x{ 0 }
{
}
strlen expects a null-terminated string. Since your x is not null-terminated, passing it to strlen is undefined behavior.
Fortunately, you do not need to call strlen, because you have variable pos that counts the number of active entries inside x:
std::cout << "length of my string = " << pos << std::endl;
for(int i = 0; i < pos ; i++) {
std::cout << x[i] << " ";
}
Is there a way to account for that extra character other than pos-1?
Yes, a better way is to increment pos only when you know that character input has been successful:
while(inFile >> x[pos]) {
pos++;
}

char array/string is empty when sent to function

I have a function that at the moment doesn't do anything because the char array I send as parameter has no value. I can write out the data before the function and get the expected output but if I write out in the function nothing come out even if It's the first thing I do.
I first write out the string and then convert it to a char array. I have also tried with just a normal string as parameter with the same result.
std::cout << block;
block = this->removeNullCharacters(block.c_str());
Output of the first cout is : "0/"
The output of the function below is nothing. Nothing at all is shown up in the console.
std::string FileSystem::removeNullCharacters(const char * input){
std::string out = "";
for(int i = 0; i < 512; ++i){
std::cout << i << ": " << input[i];
/*if(input[i] == '\0'){
return out;
}
else{
out += input[i];
}*/
}
return out;
}
Not clear at all what you try to achieve or, in other words, you question is not complete.
input is a pointer to char and points to the first element of an array of chars of size 512.
out is an empty string and returned at the end of the function.
block is schizophren, a pointer to char and a std::string at the same time i guess. You need to fix this one really.
Try this. I think you want to pass a pointer to a sequence of chars to the function and concatenate each char to the string until the end of the sequence (which is terminated by \0). Forget about the size completely and simply use the null termination as a loop condition.
std::string FileSystem::removeNullCharacters(const char * input){
std::string out = "";
for(int i = 0; input[i] != '\0'; ++i){
std::cout << i << ": " << input[i];
out += input[i];
}
return out;
}
But you gotta make sure you pass in an array of chars or a valid pointer to char (which is the beginning of a sequence of chars and the last element is \0).