I am trying to read a text file that has collections of strings into an array of objects, and am having problems with the input. I get an error that goes to istream here
*_Str = _Elem(); // add terminating null character
I don't really know much about how to use strings in C++, so any help would be appreciated.
my code:
char bird_name[MAX_LINE_LENGTH];
char* description =new char [MAX_LINE_LENGTH];
char* sound=new char [MAX_LINE_LENGTH];
int num_states= 0;
char* states[10];
bool valid = true;
char* state_name = new char [MAX_LINE_LENGTH];
for (int j =0; j<10; j++)
states[j]=new char [MAX_LINE_LENGTH];
char *input_filename = argv[1];
ifstream input(input_filename);
if (!input.is_open())
{
cerr << "Invalid filename: " << input_filename << endl;
system("pause");
return 1;
}
input.getline(bird_name, MAX_LINE_LENGTH);
char* state_num = new char [MAX_LINE_LENGTH];
while (strcmp(bird_name, "END") != 0)
{
input.getline(description, MAX_LINE_LENGTH);
consume_newline(input);
input.getline(sound, MAX_LINE_LENGTH);
consume_newline(input);
input.getline(state_num, MAX_LINE_LENGTH);
num_states = int(state_num);
consume_newline(input);
for (int k = 0; k<num_states; k++)
input.getline(states[k], MAX_LINE_LENGTH);
consume_newline(input);
consume_newline(input);
birds[num_birds++] = new Bird(bird_name, description, sound, num_states, states);
//birds[num_birds]->display();
input.getline(bird_name, MAX_LINE_LENGTH);
}
The offending code you mention, …
*_Str = _Elem(); // add terminating null character
is presumably from some standard library source code file.
Note that in your own code you should not use identifiers starting with underscore followed by uppercase, since they are reserved for the implementation (such as the code above).
The comment indicates that things go awry when the standard lib code has read a complete line of input into the buffer, and is trying to add a terminating null-byte.
That in turn indicates that the buffer is too small, or that the buffer pointer handed to the standard library code, is not even valid.
I am unable to find that in the code that you’re showing. And I suspect that the code you’re showing is not the code where the problem manifests. Please note that for the future: if at all possible, post complete code that you have tested one millisecond ago…
Anyway, it’s not necessary to know exactly where and what goes wrong (in detail) in order to fix things. You can just employ an “Alexandrian solution”. That expression refers to Alexander the Great who, when he could not find any rope end to start untying a really Bad Knot™, just sliced it in two with his sword.
So consider your declaration …
char* description =new char [MAX_LINE_LENGTH];
Now the first obvious thing that is wrong with that, glaring us in the face, is the use of an ALL UPPERCASE identifier. Reserve that for macros. Then it becomes …
char* description =new char [max_line_length];
Second, using a raw pointer, and raw new, is generally just Bad™. So get rid of that. Then it looks like …
char description[max_line_length];
Third, using a raw array like that is often a good solution, but it turns out that this one is being used for a variable length string. And for that usage, it is just Bad™. Instead use an object of some string class, such as the standard library’s std::string:
std::string description;
You need to include the [string] header for that, i.e. #include <string>.
Fourth, this variable is only used inside the loop, so move the declaration inside the loop!
Fifth, with std::string, you need to change the getline call, currently …
input.getline(description, MAX_LINE_LENGTH);
to use the freestanding getline function from the [string] header, namely …
std::getline( input, description );
Sixth, there is no error checking on input operations. You need to add error checking and error handling. Assuming that input as a std::istream, then you can check input.fail(); it’s true if some input operation has failed.
Sevent… Oh there should logically be seventh point here, since seven is a much more pleasing number than six. However, I have nothing to say that will fit into this seventh point.
Cheers & hth.,
Related
I'm trying to get the length of a character array in a second function. I've looked at a few questions on here (1 2) but they don't answer my particular question (although I'm sure something does, I just can't find it). My code is below, but I get the error "invalid conversion from 'char' to 'const char*'". I don't know how to convert my array to what is needed.
#include <cstring>
#include <iostream>
int ValidInput(char, char);
int main() {
char user_input; // user input character
char character_array[26];
int valid_guess;
valid_guess = ValidGuess(user_input, character_array);
// another function to do stuff with valid_guess output
return 0;
}
int ValidGuess (char user_guess, char previous_guesses) {
for (int index = 0; index < strlen(previous_guesses); index++) {
if (user_guess == previous_guesses[index]) {
return 0; // invalid guess
}
}
return 1; // valid guess, reaches this if for loop is complete
}
Based on what I've done so far, I feel like I'm going to have a problem with previous_guesses[index] as well.
char user_input;
defines a single character
char character_array[26];
defines an array of 26 characters.
valid_guess = ValidGuess(user_input, character_array);
calls the function
int ValidGuess (char user_guess, char previous_guesses)
where char user_guess accepts a single character, lining up correctly with the user_input argument, and char previous_guesses accepts a single character, not the 26 characters of character_array. previous_guesses needs a different type to accommodate character_array. This be the cause of the reported error.
Where this gets tricky is character_array will decay to a pointer, so
int ValidGuess (char user_guess, char previous_guesses)
could be changed to
int ValidGuess (char user_guess, char * previous_guesses)
or
int ValidGuess (char user_guess, char previous_guesses[])
both ultimately mean the same thing.
Now for where things get REALLY tricky. When an array decays to a pointer it loses how big it is. The asker has gotten around this problem, kudos, with strlen which computes the length, but this needs a bit of extra help. strlen zips through an array, counting until it finds a null terminator, and there are no signs of character_array being null terminated. This is bad. Without knowing where to stop strlen will probably keep going1. A quick solution to this is go back up to the definition of character_array and change it to
char character_array[26] = {};
to force all of the slots in the array to 0, which just happens to be the null character.
That gets the program back on its feet, but it could be better. Every call to strlen may recount (compilers are smart and could compute once per loop and store the value if it can prove the contents won't change) the characters in the string, but this is still at least one scan through every entry in character_array to see if it's null when what you really want to do is scan for user_input. Basically the program looks at every item in the array twice.
Instead, look for both the null terminator and user_input in the same loop.
int index = 0;
while (previous_guesses[index] != '\0' ) {
if (user_guess == previous_guesses[index]) {
return 0; // prefer returning false here. The intent is clearer
}
index++;
}
You can also wow your friends by using pointers and eliminating the need for the index variable.
while (*previous_guesses != '\0' ) {
if (user_guess == *previous_guesses) {
return false;
}
previous_guesses++;
}
The compiler knows and uses this trick too, so use the one that's easier for you to understand.
For 26 entries it probably doesn't matter, but if you really want to get fancy, or have a lot more than 26 possibilities, use a std::set or a std::unordered_set. They allow only one of an item and have much faster look-up than scanning a list one by one, so long as the list is large enough to get over the added complexity of a set and take advantage of its smarter logic. ValidGuess is replaced with something like
if (used.find(user_input) != used.end())
Side note: Don't forget to make the user read a value into user_input before the program uses it. I've also left out how to store the previous inputs because the question does as well.
1 I say probably because the Standard doesn't say what to do. This is called Undefined Behaviour. C++ is littered with the stuff. Undefined Behaviour can do anything -- work, not work, visibly not work, look like it works until it doesn't, melt your computer, anything -- but what it usually does is the easiest and fastest thing. In this case that's just keep going until the program crashes or finds a null.
I want to make a function that removes all the characters of ch in a c-string.
But I keep getting an access violation error.
Unhandled exception at 0x000f17ba in testassignments.exe: 0xC0000005: Access violation writing location 0x000f787e.
void removeAll(char* &s, const char ch)
{
int len=strlen(s);
int i,j;
for(i = 0; i < len; i++)
{
if(s[i] == ch)
{
for(j = i; j < len; j++)
{
s[j] = s[j + 1];
}
len--;
i--;
}
}
return;
}
I expected the c-string to not contain the character "ch", but instead, I get an access violation error.
In the debug I got the error on the line:
s[j] = s[j + 1];
I tried to modify the function but I keep getting this error.
Edit--
Sample inputs:
s="abmas$sachus#settes";
ch='e' Output->abmas$sachus#settes, becomes abmas$sachus#stts
ch='t' Output-> abmas$sachus#stts, becomes abmas$sachus#ss.
Instead of producing those outputs, I get the access violation error.
Edit 2:
If its any help, I am using Microsoft Visual C++ 2010 Express.
Apart from the inefficiency of your function shifting the entire remainder of the string whenever encountering a single character to remove, there's actually not much wrong with it.
In the comments, people have assumed that you are reading off the end of the string with s[j+1], but that is untrue. They are forgetting that s[len] is completely valid because that is the string's null-terminator character.
So I'm using my crystal ball now, and I believe that the error is because you're actually running this on a string literal.
// This is NOT okay!
char* str = "abmas$sachus#settes";
removeAll(str, 'e');
This code above is (sort of) not legal. The string literal "abmas$sachus#settes" should not be stored as a non-const char*. But for backward compatibility with C where this is allowed (provided you don't attempt to modify the string) this is generally issued as a compiler warning instead of an error.
However, you are really not allowed to modify the string. And your program is crashing the moment you try.
If you were to use the correct approach with a char array (which you can modify), then you have a different problem:
// This will result in a compiler error
char str[] = "abmas$sachus#settes";
removeAll(str, 'e');
Results in
error: invalid initialization of non-const reference of type ‘char*&’ from an rvalue of type ‘char*’
So why is that? Well, your function takes a char*& type that forces the caller to use pointers. It's making a contract that states "I can modify your pointer if I want to", even if it never does.
There are two ways you can fix that error:
The TERRIBLE PLEASE DON'T DO THIS way:
// This compiles and works but it's not cool!
char str[] = "abmas$sachus#settes";
char *pstr = str;
removeAll(pstr, 'e');
The reason I say this is bad is because it sets a dangerous precedent. If the function actually did modify the pointer in a future "optimization", then you might break some code without realizing it.
Imagine that you want to output the string with characters removed later, but the first character was removed and you function decided to modify the pointer to start at the second character instead. Now if you output str, you'll get a different result from using pstr.
And this example is only assuming that you're storing the string in an array. Imagine if you actually allocated a pointer like this:
char *str = new char[strlen("abmas$sachus#settes") + 1];
strcpy(str, "abmas$sachus#settes");
removeAll(str, 'e');
Then if removeAll changes the pointer, you're going to have a BAD time when you later clean up this memory with:
delete[] str; //<-- BOOM!!!
The I ACKNOWLEDGE MY FUNCTION DEFINITION IS BROKEN way:
Real simply, your function definition should take a pointer, not a pointer reference:
void removeAll(char* s, const char ch)
This means you can call it on any modifiable block of memory, including an array. And you can be comforted by the fact that the caller's pointer will never be modified.
Now, the following will work:
// This is now 100% legit!
char str[] = "abmas$sachus#settes";
removeAll(str, 'e');
Now that my free crystal-ball reading is complete, and your problem has gone away, let's address the elephant in the room:
Your code is needlessly inefficient!
You do not need to do the first pass over the string (with strlen) to calculate its length
The inner loop effectively gives your algorithm a worst-case time complexity of O(N^2).
The little tricks modifying len and, worse than that, the loop variable i make your code more complex to read.
What if you could avoid all of these undesirable things!? Well, you can!
Think about what you're doing when removing characters. Essentially, the moment you have removed one character, then you need to start shuffling future characters to the left. But you do not need to shuffle one at a time. If, after some more characters you encounter a second character to remove, then you simply shunt future characters further to the left.
What I'm trying to say is that each character only needs to move once at most.
There is already an answer demonstrating this using pointers, but it comes with no explanation and you are also a beginner, so let's use indices because you understand those.
The first thing to do is get rid of strlen. Remember, your string is null-terminated. All strlen does is search through characters until it finds the null byte (otherwise known as 0 or '\0')...
[Note that real implementations of strlen are super smart (i.e. much more efficient than searching single characters at a time)... but of course, no call to strlen is faster]
All you need is your loop to look for the NULL terminator, like this:
for(i = 0; s[i] != '\0'; i++)
Okay, and now to ditch the inner loop, you just need to know where to stick each new character. How about just keeping a variable new_size in which you are going to count up how long the final string is.
void removeAll(char* s, char ch)
{
int new_size = 0;
for(int i = 0; s[i] != '\0'; i++)
{
if(s[i] != ch)
{
s[new_size] = s[i];
new_size++;
}
}
// You must also null-terminate the string
s[new_size] = '\0';
}
If you look at this for a while, you may notice that it might do pointless "copies". That is, if i == new_size there is no point in copying characters. So, you can add that test if you want. I will say that it's likely to make little performance difference, and potentially reduce performance because of additional branching.
But I'll leave that as an exercise. And if you want to dream about really fast code and just how crazy it gets, then go and look at the source code for strlen in glibc. Prepare to have your mind blown.
You can make the logic simpler and more efficient by writing the function like this:
void removeAll(char * s, const char charToRemove)
{
const char * readPtr = s;
char * writePtr = s;
while (*readPtr) {
if (*readPtr != charToRemove) {
*writePtr++ = *readPtr;
}
readPtr++;
}
*writePtr = '\0';
}
I have an array of character arrays that is split based on a pipe ('|') operator (example below) and the function I am using to create this array seems to work on occasion, and then on occasion, it will create the array then abort and give me one of two different errors.
I am not sure what I am doing wrong? Particularly I am not sure why it creates successfully every time but then seems to break after creation about half the time, regardless of the input.
Example array:
"here is | an example | input" = {"here is", "an example", "input"}
Errors:
Error in './msh': malloc(): memory corruption (fast): 0x000...
Error in './msh': free(): invalid pointer: 0x0000....
Code:
char** allArgs = new char*[100];
void createArgArrays(const char* line) {
char* token;
token = strtok((char*)line, "|");
int i = 0;
while(token != NULL) {
allArgs[i] = token;
i++;
token = strtok(NULL, "|");
}
}
Where I call the code:
string input;
getline(cin, input);
createArgArrays(input.c_str());
Any insight/help is greatly appreciated.
c_str() returns a const char *. strtok() modifies the string it refers to.
Per http://www.cplusplus.com/reference/string/string/c_str/:
c++98
A program shall not alter any of the characters in this sequence.
Don't cast away const to force things to "work".
A few things:
The C++ way is sometimes different than the C way.
Andrew Henle's point about casting should be carved into stone tablets.
If you really want to use a C function, try walking the string using strchr().
Also, try something like std::vector<std::string> (see std::vector::push_back) to store your string chunks - it'll be a bit cleaner and avoids an arbitrary cap on the size of allArgs.
Another thing you could look at is boost::split(), which probably does exactly what you want anyway.
My boss told me to look at the following code and tell him what the potential security vulnerabilities were. I'm not very good at this kind of thing, since I don't think in the way of trying to hack code. All I see is that nothing is declared private, but other than that I just don't know.
#define NAME_SIZE (unsigned char) 255
// user input should contain the user’s name (first name space
// middle initial space last name and a null
// character), and was entered directly by the user.
// Returns the first character in the user input, or -1 if the method failed.
char poor_method(char* user_input, char* first, char *middle, char* last)
{
char*buffer;
char length;
// find first name
buffer = strtok(user_input, " ");
if(buffer==0)
{
return -1;
}
length = strlen(buffer);
if(length <= NAME_SIZE)
{
strcpy(first, buffer);
}
// find middle name
buffer = strtok(NULL, " ");
if(buffer==0)
{
return-1;
}
if(middle)
*middle = buffer[0];
// find last name
buffer = strtok(NULL, "\0");
length = strlen(buffer);
if(length <= NAME_SIZE)
{
strcpy(last, buffer);
}
// Check to make sure that all of the user input was used
buffer = strtok(NULL, "\0");
if(buffer != NULL)
{
return-1;
}
return first[0];
}
What security vulnerabilities are there?
Get good at writing secure code
You most likely don't want systems that you are responsible for finding their way onto bugtraq or cve. If you don't understand it, be honest with your boss. Tell him you don't understand and you want to work on it. Pick up Writing Secure Code. Read it, learn it, love it. Asking this question on SO and giving your boss the answer definitely doesn't help you in the long run.
Then look at the sample code again :)
What I saw (by no means a complete list):
There's no guarantees you're going to get a char pointer which points to a null-terminating string (unless you're allowed to make that assumption, not really a safe one to make).
strtok and strcpy are the C way of doing things and come with the fun stuff of programming C code. If you must use them, so be it (just make sure you can guarantee you're inputs to these functions will indeed be valid). Otherwise, try switching your code to use std::string and the "C++ way" (as Cat Plus Plus put it)
I'm assuming this is a typo:
charpoor_method(
You're missing a space between char and poor_method(
You're not checking if first or last are indeed valid pointers (unfortunately, the best you can do is to check them against NULL).
There's no guarantee that the buffers first or last can indeed hold whatever you're copying to them.
Another typo:
returnfirst[0];
missing space between return and first[0]
Learning to write secure code is something that's very important to do. Follow Brecht's advice and get good at it.
Ok strtok assumes user_input is NULL terminated, this might not be true.
charlength = strlen(buffer);
if(length <= NAME_SIZE)
{
strcpy(first, buffer);
}
charlenght here is undeclared, so is length, they should be declared as unsigned int.
strlen wont count the '\0' as a part of the length, so later strcpy will copy the '\0' to whatever is after First if the len of buffer is 255 + 1('\0')
Also is unknown if char *first size is, it should be NAME_SIZE but the comparisson should be
length <= NAME_SIZE - 1
or allocate char *first to NAME_SIZE + 1
I'd probably rewrite the whole thing, is quite ugly.
Rather than using strcpy(), use strncpy() with a specific length parameter, as that function, like strtok(), assumes a NULL-terminated buffer for the source, and that may not be the case, giving you a buffer overflow for the data copied into the buffer pointed to by either first or last. Additionally, you have no idea how long the buffers are that have been allocated for first and last ... Don't assume that the user of your function has properly allocated enough memory to copy into unless they've passed you a parameter telling you there are enough memory slots in the buffers. Otherwise again, you could (and most likely will) end-up with buffer overflows.
Also you may want to use the restrict keyword if you're using C99 in order to prevent the caller of your function from aliasing the same memory location for buffer, first, and last.
Hey everyone, thanks for taking the time to address my problem. I've looked at so much material at this point that I've just started getting more and more confused. Basically, I'm writing a simple segment of code that parses a string. Please understand that my question is NOT about parsing. I am using C++ and have never used C before and possess a little bit of c++ experience (introductory experience, I'm still a newbie).
struct parsedString{
char chunk1[50];
char chunk2[10];
char chunk3[50];
};
main(char* bigstring)
{
parsedString ps;
ps = parseMe(bigString)
cout << ps.chunk1 << endl;
cout << ps.chunk2 << endl;
cout << ps.chunk3 << endl;
}
parsedString parseMe(char* stringToParse)
{
char* parseStr = stringToParse;
parsedString ps;
ps.chunk1 = first x chars;
ps.chunk2 = next y chars;
ps.chunk3 = last z chars;
return ps;
}
Obviously this is not working code, I didn't want to throw up all the extra stuff since it would be tougher to read through and I'm pretty sure my problem is a newbie c/c++ problem and something about memory allocation or something like that...
Basically when the main function gets to printing the strings from the parsedString it prints out exactly what I want it to, plus garbage characters. I'm entering the values for each array ps.chunk using
ps.chunk1[i] = *parseStr
since parseStr gets me each individual character. I can't figure out where the garbage characters are coming from, does it have something to do with how I am accessing the big string? Originally I used char in the struct instead of arrays and when I printed from within the parseMe() function they would come out great but they would turn into gibberish when I accessed it from the main function. Any help is appreciated, thanks so much.
If something is unclear please let me know I'll do my best to elaborate.
It's not clear why you're trying to do this with '\0' terminated
strings, when C++ has a perfectly usable string class, but
supposing some pedagogical reasons: are your strings '\0'
terminated? How do you extract and copy the first x chars into
ps.chunk1? How do you ensure that it has a '\0'?
If you really want to get exactly n characters, you have to:
assert(strlen(parseStr) >= n);
, copy them into the target (which must contain at least n+1 char's),
memcpy(ps.chunk1, parseStr, n);
, and add the final '\0':
ps.chunk1[n] = '\0';
(And, of course, advance parseStr: parseStr += n;)
Or you can simply use std::string everywhere, and write
something like:
ps.chunk1(stringToParse.substr(startPosition, length));
As pointed out by others, you should use std::string to represent strings, and save yourself all the trouble. This could look like this:
struct parsedString{
std::string chunk1;
std::string chunk2;
std::string chunk3;
};
parsedString parseMe(const std::stirng & stringToParse) {
parsedString result;
// just an example - this assigns the first two characters of stringToParse
// to chunk1
result.chunk1 = stringToParse.substr(0, 2);
// get the other chunks
return result; // return the result
}
The above code should illustrate the usage. You can find more information on std::string here.
This could be happening due to a couple of reasons.
When you declare parsedString ps; it would be good to initialize the structure and make sure that you are receiving clean memory blocks to work with.parsedString ps = {0}; Some platforms don't do this and it's up to you to zero the memory before using it.
char* strings must end with the \0 character. This character signals the end of a char*. This is mandatory! Not inserting it at the end of the string will most probably make the print operation (for instance) display contents beyond the limits of the array giving you garbage characters. This is automatically achieved by zeroing all the struct as I suggest above.