compiler adding random characters to my char array - c++

I have a function called SearchArray() which calls another function called SearchRecords(char StudentNo[]) to check the database array of gRecs for a match in student numbers.
When i run the debugger the value of StudentNo is being shown as StudentNo = 0x22fde0 "12345678" if StudentNum = "12345678".
What are these additional characters?
SearchArray() function
void SearchArray(){
char studentNum[8];
cout << "Enter student number: ";
cin >> studentNum;
char i = SearchRecords(studentNum);
if (gRecs[i].studentNumber != studentNum){
cout << "Record not found" << endl;
}
else {
PrintRecord(i);
}
}
SearchRecords() function
int SearchRecords(char StudentNo[])
{
for (int i = 0; i < gNumRecs; i++){
if(gRecs[i].studentNumber == StudentNo)
{
return i;
}
}
return -1; //not found
}

Do you mean the "0x22fde0"? Those aren't in your character array, your character array only contains the part in quotes ("12345678"). The hexadecimal number 0x22fde0 is the address of the first character. In C/C++, any array is really just a pointer to the first element: the value of the variable is the address of the first element. So the debugger is showing you that address value. But it also knows that character arrays usually store strings, so it is also helpfully showing you the contents of that array as a string.

As this comment notes, you're comparing pointers not strings. You'll save yourself many headaches by changing your studentNumber type to std::string. This will allow you to use comparison operators(==,!=,<,<=,>,>=) with either a std::string or a raw string(char*) on the right side. I highly recommend reading up on strings at tutorialspoint.com and cplusplus.com.
When posting in the future, please post any relevant custom data structures(such as the layout of your gRecs element type), it helps us solve the problem faster.

Related

Why does assigning a value to a string in a struct crash the program?

I have commented out the problematic string, attempted to pass the input to a string that is not a member of the struct, then passing it to the correct string, to no avail. To achieve the intended function, the string must go through this struct. Where is it going wrong?
Structure code:
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;
class passingdata
{
public:
passingdata()
{
//constructor
};
~passingdata()
{
//destructor
};
int convertedResponse;
const string headers[4] = {"Labor/Materials", "Cost (per unit)", "Total Units", "Total Cost"}; //this is all to be written to a file later.
struct dynInputs
{
string name;
int perCost;
int unitTotal;
int totalCost = perCost * unitTotal;
};
void acceptInputs()
{
string name = "";
string response = "";
const string positiveResponse = "yes";
cout << "Would you like to insert a label?" << endl;
getline(cin, response);
if (response == positiveResponse)
{
populateSaveData();
}
else
{
//nothing yet
}
}
void populateSaveData()
{
if (convertedResponse = 1)
{
cout << "How many labels would you like to create?" << endl;
int labelCount;
cin >> labelCount;
cin.clear();
int labelsNeeded = labelCount;
dynInputs* dynamicInputs;
dynamicInputs = new dynInputs[labelsNeeded];
while (labelsNeeded > 0)
{
cout << "please type the name for this row" << endl;
cin.ignore();
//string tempName = "";
//getline(cin, tempName); this works!
getline(cin, dynamicInputs[labelsNeeded].name); //this breaks, goes to trash memory when done this way
system("pause");
cin.clear();
//tempName = dynamicInputs[labelsNeeded].name; breaks as well
cout << dynamicInputs[labelsNeeded].name << endl;
//cout << tempName << endl;
system("pause");
cout << "please type the cost of the unit, and the number of units" << endl;
cin >> dynamicInputs[labelsNeeded].perCost;
cin.clear();
cin >> dynamicInputs[labelsNeeded].unitTotal;
cin.clear();
labelsNeeded--;
}
cout << dynamicInputs[0].unitTotal << endl;
The dynamicInputs[labelsNeeded] array points to junk memory, yet I'm unsure of why it only crashes assigning value to the string.
In labelsNeeded you store the size of the array.
Then in the first iteration you use labelsNeeded to index into your array. Since C++ indexes an array starting from 0, the largest possible valid index is (the size of the array) - 1.
Eg.: For an array of size 4, your valid index range is [0, 1, 2, 3].
Now what you are doing is setting labelsNeeded to equal labelCount and then allocate an array of the size equalig labelsNeeded. And then in the first iteration you use the value of labelsNeeded as an index with this original value for accessing an element in your array. Which goes past the valid range of your array. Hence the program crashes.
I see that at the and of the iteration you decrement labelsNeeded but that is too late considering that you already tried to use the original value earlier in the code.
Your labelsNeeded > 0 condition for your while loop is also incorrect if you are using this "decrement the index at the end of the iteration" solution since it will fail to write the first (at index 0) element of your array.
Try moving the labelsNeeded-- line to the beginning of the iteration.
Note:
As to "why it only crashes assigning value to the string".
C++ (or rather the runtime) does not care whether your pointer points to a valid address or not. Simply because a pointer is just a memory address. By it self it is just a number stored in memory. A pointer that references invalid memory will only crash your program (or do other weird stuff) if you want to dereference it or in other words -> If you want to actually use the pointer to access that place in memory. It is not the "invalid" memory address in the pointer that crashes but the act of trying to access the memory at that address. The distinction may look subtle but is very important nonetheless. You can have any number of "null pointers" in the program as long as you don't try to dereference null.
Note 2:
Yours is an especially interesting mode of failure since it can fail in one of two places:
Since you are indexing an element that is one past the end of the array, that may as well coincide with the end of the heap that was assigned to the program. So it may crash there. But... Most likely your array is not allocated in such a place and there will still be accessible heap past the end of your array so dereferencing one element past your array may as well give you "something" and by something I mean some memory content cast to the type that you have. But of course from your point of view that is some random data.
If execution survived the previous section and now you have a struct with random data, you also have your string in your struct that is also filled with random garbage. Which means its pointer to the actual string content is also random (most likely pointing somewhere before or past your addressable space) as well as its size and other state information also being garbage. So if you reassign that string then its original content pointer will likely be accessed (eg.: deallocation) which will result in a crash.

Why does my function not switch the first character with the last one of my string?

I picked up a challenge on r/dailyprogrammer on reddit which wants me to match a necklace and put the last letter at the beginning of a string. I've considered using nested for loops for this but this has made me really confused.
Instead I chose the way of replacing the last with the first character in an if-statement. But I am not getting my desired output with it, though I've tried everything what comes into my mind.
I used even std::swap() which didn't lead me to success either.
Here's the code:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string same_necklace(string& sInput, string& sOutput)
{
for (string::size_type i = 0; i < sInput.size(); i++)
{
if (sInput[i] == sInput.size())
{
sInput[0] = sInput[sInput.size()];
}
}
for (string::size_type j = 0; j < sOutput.size(); j++)
{
if (sOutput[j] == sOutput.size() - 1)
{
sOutput[0] = sOutput[sOutput.size()];
}
}
return sInput, sOutput;
}
int main()
{
system("color 2");
string sName{ "" };
string sExpectedOutput{ "" };
cout << "Enter a name: ";
cin >> sName;
cout << "Enter expected output: ";
cin >> sExpectedOutput;
cout << "Result: " << same_necklace(sName , sExpectedOutput) << endl;
return 0;
}
And of course the link to my challenge (don't worry, it's just Reddit!):
https://www.reddit.com/r/dailyprogrammer/comments/ffxabb/20200309_challenge_383_easy_necklace_matching/
While I am waiting (hopefully) for a nice response, I will keep on trying to solve my problem.
In your if you compare the value of the current index (inside the loop) with the size of the string. Those are two unrelated things.
Also, you use a loop though you only want to do something on a single, previously known index.
for (string::size_type i = 0; i < sInput.size(); i++)
{
if (sInput[i] == sInput.size())
{
sInput[0] = sInput[sInput.size()];
}
}
You could change the if condition like this to achieve your goal:
if (i == sInput.size()-1) /* size as the index is one too high to be legal */
But what is sufficient and more elegant is to drop the if and the loop. completely
/* no loop for (string::size_type i = 0; i < sInput.size(); i++)
{ */
/* no if (sInput[i] == sInput.size())
{*/
sInput[0] = sInput[sInput.size()-1]; /* fix the index*/
/* }
} */
I.e.
sInput[0] = sInput[sInput.size()-1]; /* fix the index*/
Same for he output, though you got the correct index already correct there.
This is not intended to solve the challenge which you linked externally,
if you want that you need to describe the challenge completely and directly here.
I.e. this only fixes your code, according to the desription you provide here in the body of your question,
"put the last letter at the beginning of a string".
It does not "switch" or swap first and last. If you want that please find the code you recently wrote (surely, during your quest for learning programming) which swaps the value of two variables. Adapt that code to the two indexes (first and last, 0 and size-1) and it will do the swapping.
So much for the loops and ifs, but there is more wrong in your code.
This
return sInput, sOutput;
does not do what you expect. Read up on the , operator, the comma-operator.
Its result is the second of the two expressions, while the first one is only valuated for side effects.
This means that this
cout << "Result: " << same_necklace(sName , sExpectedOutput) << endl;
will only output the modified sExpectedOutput.
If you want to output both, the modified input and the modified output, then you can simply
cout << "Result: " << sName << " " << sExpectedOutput << endl;
because both have been given as reference to the function and hence both contain the changes the function made.
This also might not answer the challenge, but it explains your misunderstandings and you will be able to adapt to the challenge now.
You have not understand the problem i guess.
Here you need to compare two strings that can be made from neckless characters.
Lets say you have neckless four latters word is nose.
Combination is possible
1)nose
2)osen
3)seno
4)enos
your function (same_necklace) should be able to tell that these strings are belongs to same necklace
if you give any two strings as inputs to your function same_necklace
your function should return true.
if you give one input string from above group and second input string from other random word thats not belongs to above group, your function should return false.
In that sense, you just take your first string as neckless string and compare other string with all possible combination of first string.
just move move you first latter of first input string to end and then compare each resulting string to second input string.
below is the function which you can use
void swap_character(string &test)
{
int length = test.length();
test.insert(length, 1, test[0]);
test.erase(0, 1);
}

What is the length of my array?

Hello everyone I'm having trouble with strlen and arrays, it keeps saying my string length is only one? If anyone could help it would be great here's my code:
#include <iostream>
using namespace std;
#include <cstring>
int main()
{
char word1[20];
int len = strlen(word1);
cout << "enter a word!\n";
cin.get(word1, 20, '\n'); cin.ignore(50,'\n');
cout << len;
}
Just read the back and forth in the comments, updating my answer to try and give some more intuition behind what's going on.
char word1[20]; Sets a place in your computer's memory that can eventually be filled by data up to 20 characters. Note that this statement alone does not "clear" the memory of whatever is currently there. As sfjac has pointed out, this means that literally anything could be in that space. It's highly unlikely that whatever is in this space is a character or anything your code could readily understand.
int len = strlen(word1); Creates an integer and sets it equal to the value of the number of characters currently in word1. Note that, because we have not specified any content for word1, you're taking the length of whatever happened to be in that memory space already. You've limited the maximum to 20, but in this case, whatever data junk is in there is giving you a length of 1.
cout << "enter a word!\n"; Prompt the user for a word
cin.get(word1, 20, '\n'); cin.ignore(50,'\n'); Get the word, store it in word1. At this point, word1 is now defined with actual content. However - you've already defined the variable len. The computer does not know to automatically redefine this for you. It follows the steps you provide, in order.
cout << len; Print the value stored in len. Because len was created prior to the user entering their data, len has absolutely nothing to do with what the user entered.
Hope this helps give you some intuition that will help beyond this one question!
#Chris is correct but perhaps a small explanation. When you declare a character array like char word1[20] on the stack, the array will not be initialized. The strlen function computes the length of the array by counting the number of characters from the address of word1 to the first null byte in memory, which could be pretty much anything.
I highly recommend using std::string for text.
If you must use character arrays:
Define a named identifier for the capacity.
Define the array using the named identifier.
The capacity should account for a terminating nul, '\0', character to
mark the end of the maximum text length.
Using the above guidelines you have the simple program:
int main(void)
{
std::string a_word_string;
std::string line_of_text_string;
const unsigned int c_string_capacity = 32U;
char c_string[c_string_capacity];
// The std::string functions
cout << "Enter some text: ";
getline(cin, line_of_text_string); // read a line of text
cout << "\nEnter a sentence: ";
cin >> a_word_string;
cin.ignore(10000, '\n'); // Ignore remaining text in the buffer.
// The C-style string functions
cout << "Enter more text: ";
cin.read(c_string, c_string_capacity);
c_string[c_string_capacity - 1] = '\0'; // Insurance, force end of string character
cout << "You entered " << (strlen(c_string)) << " characters.\n";
return EXIT_SUCCESS;
}
The std::string class is more efficient and can handle dynamically size changes.
The length of the array is the value of c_string_capacity which was used when defining the array.
The length of the text in the array is defined as strlen(c_string), which is the number of characters before the terminating nul is found.
You have to calculate len after reading in word1, otherwise you are left with undefined behaviour.
char word1[20];
cout << "enter a word!\n";
cin.get(word1, 20, '\n'); cin.ignore(50,'\n');
int len = strlen(word1);
cout << len;
It's a good idea to always initialize objects when you declare them. Since objects inside of a scope are not guaranteed to be initialized.
In C++11 for example, you can do this:
char arr[10]{}; // this will initialize the objects in the array to default.
char arr[10]{0}; // the same.

Length of string[] (number of elements in a string)

I want to cout my string, everything works as it should, but when the string is shown, it immediately shows me the "example_4578.exe has stopped running" error. I have noticed that the problem is in the i < str[32].length part, because when I change it to i < 3, it works without any problem. How should I solve this?
std::string str[32];
cin >> str[1];
cout << "str[1]=" << str[1] << endl;
cin >> str[2];
cout << "str[2]=" << str[2] << endl;
for (int i = 0; i < str[32].length; i++)
{
cout << str[i];
}
EDIT 1.
I've made a huge mistake. I actually want to find the "number" of elements/words in "str". In my example, I have only designed two cins. But I actually want to design a "for" loop later on, so that the user can input as many words as he wants, so if he inputs 4 words, I want that code to return those number of words to me. How should I do this? In other words, how can I find out how many elements are in "str"?
Couple of things:
C++ is 0-indexed. What this means is that std::string str[32] has indices that go from 0 to 31, and str[32] should not be accessed. This will cause a crash.
str[31].length() (which is presumably what you wanted) is the length of the last string, not the length of the array. The length of the array is 32, and your loop should read for(int i = 0; i < 32; i++).
The main problem is that you are accessing an element (number 32) that is out of the bounds (0 - 31). To solve this problem and not repeat it again in the future use a range-for loop:
std::string str[32];
for (auto s : str)
std::cout << s;
str[32].length is not what you think.
I guess you meant somthing like: length of a 32-elements array. Right?
What you've written is pointer to funciton length of 33rd element of array.
This is because the types are:
std::string str[32]; // `str` is 32-element array of `std::strings`
str[32]; // `std::string` taken from 33rd position in array `str` (arrays' indexing starts at 0)
std::string has a member function named size_t std::string::length(). When referenced by name, you get its address.
To achieve what you wanted, you'd need to write:
for (int i = 0; i < 32; i++) {
cout << str[i];
}
Unfortunately, plain arrays don't have length (or anything similar) built in. So, you'd either need to use a constant, or (better) use a container, such as std::vector.

Accessing data inside an array via pointer error

I have 2 files in msg format. msg format is not important here.
car.msg
int speed;
int width;
cararr.msg
car mycar[];
I want to print all the information about all the cars that are present but I have no clue about the number of cars present(how big is the array) so I use the following technique to print the information.
so I do this:
cararr* ptr2car;
for(int i=0;mycar[i] != '\0'; i++){
cout << ptr2car->mycar[i].speed <<endl;
cout << ptr2car->mycar[i].width <<endl;
}
Despite this, I am receiving errors. I do not know what did I do wrong. I have no clue what approach should I use to get this output. please Help
Also why should I take a pointer to cararr, when I can just take an instance of cararr inst2car and do something like this:
cararr inst2car;
for(int i=0;mycar[i] != '\0'; i++){
cout << inst2car.mycar[i].speed <<endl;
cout << inst2car.mycar[i].width <<endl;
}
thanks
In general you need to know exactly what's at the end of the array. You need some sort of sentinel value to use as a delimiter to indicate the end of the array.
'\0' used in c strings is an example of such delimiter.
You need to ensure the last element in the array is such delimiter and check for it in the condition.
It's hard to give you more specific answer with such generic question.
For example, if you knew the last element will have speed -1, you can use that:
for(int i=0;mycar[i].speed != -1; i++) {