Replacements for deprecated strcpy/strcat when using char* - c++

I have code for a 'zombie translator' as an example from my professor. From what I can tell it takes a string of english words and applies a few rules to it via functions. It currently uses strcpy and strcat to do this, however it will not compile even if I change them to strcpy_s. Without including the other functions (for the sake of space), here is my main function as an example
int main()
{
char english[MAX];
char zombie[MAX];
char zombie_word[MAX];
int pos_e; /* Current position in english line of text */
int pos_z; /* Current position in line of translated zombie text */
while (1) {
pos_e = 0;
pos_z = 0;
strcpy(zombie, "");
cout << ("Enter English text: ");
cin >> english;
/* This loop translates the line from english to zombie. */
do
{
get_next_word(english, &pos_e, zombie, &pos_z);
translate_word(english, &pos_e, zombie_word, &pos_z);
strcat(zombie, zombie_word);
} while (pos_e < strlen(english));
print_translation(zombie);
}
return 0;
}
So more specifically, what should i do to the line strcat(zombie, zombie_word); to make it compile properly in Visual Studio 2015?
It's not for a grade, I just really want to be able to understand this before the midterm, and it's a bit difficult to play around with it. I would prefer not to have to disable it through _CRT_SECURE_NO_WARNINGS so that I know what to do if I need to do something similar.
Perhaps changing the char variables into strings or something like that? I've been looking around for awhile and can't find the actual process.
Thank you very much for any assistance, I greatly appreciate your time.

From Microsoft: strncat_s
You need to include the length of the array to prevent buffer overflow dangers.
The API is:
errno_t strncat_s(
char *strDest,
size_t numberOfElements,
const char *strSource,
size_t count
);
numberOfElements is size of destination array.

Related

C++, how to remove char from a string

I have to remove some chars from a string, but I have some problems. I found this part of code online, but it does not work so well, it removes the chars but it even removes the white spaces
string messaggio = "{Questo e' un messaggio} ";
char chars[] = {'Ì', '\x1','\"','{', '}',':'};
for (unsigned int i = 0; i < strlen(chars); ++i)
{
messaggio.erase(remove(messaggio.begin(), messaggio.end(), chars[i]), messaggio.end());
}
Can someone tell me how this part of code works and why it even removes the white spaces?
Because you use strlen on your chars array. This function stops ONLY when it encounters a \0, and you inserted none... So you're parsing memory after your array - which is bad, it should even provoke a SEGFAULT.
Also, calling std::remove is enough.
A correction could be:
char chars[] = {'I', '\x1','\"','{', '}',':'};
for (unsigned int i = 0; i < sizeof(chars); ++i)
{
std::remove(messaggio.begin(), messaggio.end(), chars[i]) ;
}
Answer for Wissblade is more or less correct, it just lacks of some technical details.
As mentioned strlen searches for terminating character: '\0'.
Since chars do not contain such character, this code invokes "Undefined behavior" (buffer overflow).
"Undefined behavior" - means anything can happen, code may work, may crash, may give invalid results.
So first step is to drop strlen and use different means to get size of the array.
There is also another problem. Your code uses none ASCII character: 'Ì'.
I assume that you are using Windows and Visual Studio. By default msvc compiler assumes that file is encoded using your system locale and uses same locale to generate exactable. Windows by default uses single byte encoding specific to your language (to be compatible with very old software). Only in such chase you code has chance to work. On platforms/configuration with mutibyte encoding, like UTF-8 this code can't work even after Wisblade fixes.
Wisblade fix can take this form (note I change order of loops, now iteration over characters to remove is internal loop):
bool isCharToRemove(char ch)
{
constexpr char skipChars[] = {'Ì', '\x1','\"','{', '}',':'};
return std::find(std::begin(skipChars), std::end(skipChars), ch) != std::end(skipChars);
}
std::string removeMagicChars(std::string message)
{
message.erase(
std::remove_if(message.begin(), message.end(), isCharToRemove),
message.end());
}
return message;
}
Let me know if you need solution which can handle more complex text encoding.

Handling strings inside Files [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to save data from a file into an array but I've had no luck for now. It's easy to save data after it was read from the file in case it's just numbers, but for example if I'm trying to save strings, the program keeps crashing over and over again. I'm using fscanf(); function since the whole .txt file is written in the same format: "First Name, Last Name". Now then, I've tried using the for loop in this way:
char *firstName = (char*)malloc(sizeof(char)*10240);
char *lastName = (char*)malloc(sizeof(char)*10240);
for(int i = 0; i<10; i++){
fscanf(fp, "%s %s", firstName[i],lastName[i]);
}
And that's where it crashes.
Pure C code:
You have to allocate the array of arrays first, then allocate each string one by one
It's best to scan the strings into temp strings with a big size, and duplicate the strings later.
int i,nb_names = 10;
char **firstName = malloc(sizeof *firstName * nb_names);
char **lastName = malloc(sizeof *lastName *nb_names);
char tempn[1000],templ[1000];
for(i = 0; i<nb_names; i++){
fscanf(fp,"%s %s", tempn,templ);
firstName[i] = strdup(tempn);
lastName[i] = strdup(templ);
}
Note that I have changed for (int i to for (i because it is not C compliant but rather C++ compliant (or C99, not sure).
For C++, drop the mallocs and use std::vector and std:string instead.
I'd recommend to use C++ if you can. I answered a lot of C/C++ questions on people trying (and failing) to allocate 2D arrays properly (including me 5 minutes ago damn :)). C++ using C++ library code is much clearer.
Full C++ example, reading from standard input
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
int nb_names = 10;
vector<string > firstName(nb_names);
vector<string > lastName(nb_names);
for(int i = 0; i<nb_names; i++){
cin >> firstName[i];
cin >> lastName[i];
}
return 0;
}
The error in your code is : firstName[i] is a character not a string but you use it like a string by using %s instead of %c.
you should use a char ** instead of char *.
char **firstName = (char**)malloc(10*sizeof(char)*10240);
I think also that 10240 is too much for firstName. Use 255 or less.

In C++ while using cin.get(), how can I not limit the number of characters a user can enter?

Im trying to get a users input using cin.get() but I dont want to limit the amount of characters that they can enter. How can I do this?
EDIT: I guess a better way to phrase this would be: How can I dynamicaly change the character array to fit the length of the users input?
This is a strange requirement for a C++ program. You can of course go the C way and simply keep on getting more memory whenever your input outgrows the currently available memory. It goes something like this (warning: code fragments ahead):
while(cin.get(c)) {
if (cur_pos == cur_len) {
cur_len = grow_charbuf(buffer, cur_len);
}
buffer[cur_pos++] = c;
}
Here, the grow function is where it gets ugly. It needs to allocate a larger piece of memory, copy the contents of the current buffer to the beginning of that, dealocate the memory occupied by the current buffer, and return the new size. For example, something along these lines:
char* new_charbuf(size_t len) {
return new char [len];
}
size_t grow_charbuf(char* buf, size_t cur_len) {
size_t new_len = cur_len * 2;
char* new_buf = new char [new_len];
// copy old buffer contents to new buffer
delete[] buf;
buf = new_buf;
return new_len;
}
And you can then use it as follows:
cur_len = 1000; // or whatever
char* buffer = new_charbur(cur_len);
// write into the buffer, calling grow_charbuf() when necessary
// and don't forget to free the memory once you are done...
// or don't free it, if the program eventually exits anyway
This is terrible code. It might work, but you should never ever do this in C++ if you can avoid it. Apart from this, I have avoided handling any error conditions or exceptions that this code might cause. It is meant just to illustrate the idea.
Managing your memory manually is a bad idea because it requires a lot of code and is not easy to get right. You can get away with less if your program has a known, limited life-span.
Don't use characters array at all. Use std::string or other standard containers.
And of cause learn to use streams.
Here an example. It reads as many characters as the user inputs until the user presses enter. As you cna see, there is no explicite buffer-size required:
/////TEST PUT ANYWHERE IN GLOBAL SCOPE
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int test()
{
//SET BP HERE AND STEP THROUGH
string line;
getline(cin,line);
std::stringstream user_input( line );
while(!user_input.eof())
{
string word;
user_input >> word;
cout << word << endl;
}
return 0;
}
static int _test = test();
/////END TEST
You need a cin.getline(). In other words you need to have a specified size of char array and use it like so:
Using cin.get()
char str[100];
char sayHello[100];
cin.get(str, 100);
// make sure to add cin.ignore() or program will terminate right before next cin().
cin.ignore();
cout << str << endl;
cin.get(sayHello, 100);
cout << sayHello;
or for cin.getline()
char input[100];
cin.ignore(); // stops the sentence from truncating.
cin.getline(input,sizeof(input));
You could also use getline() for strings like so:
string name;
getline(cin, name);
The problem is that in c++ when receiving input your cin looks for the 0 aka the space in your sentence. It then ends thinking that was the end.

Read a string with ncurses in C++

I'm writing a text-based game in C++. At some point, I ask the user to input user names corresponding to the different players playing.
I'm currently reading single char from ncurses like so:
move(y,x);
printw("Enter a char");
int char = getch();
However, I'm not sure how to a string. I'm looking for something like:
move(y,x);
printw("Enter a name: ");
std::string name = getstring();
I've seen many different guides for using ncurses all using a different set of functions that the other doesn't. As far as I can tell the lines between deprecated and non-deprecated functions is not very well defined.
How about this?
std::string getstring()
{
std::string input;
// let the terminal do the line editing
nocbreak();
echo();
// this reads from buffer after <ENTER>, not "raw"
// so any backspacing etc. has already been taken care of
int ch = getch();
while ( ch != '\n' )
{
input.push_back( ch );
ch = getch();
}
// restore your cbreak / echo settings here
return input;
}
I would discourage using the alternative *scanw() function family. You would be juggling a temporary char [] buffer, the underlying *scanf() functionality with all its problems, plus the specification of *scanw() states it returns ERR or OK instead of the number of items scanned, further reducing its usefulness.
While getstr() (suggested by user indiv) looks better than *scanw() and does special handling of function keys, it would still require a temporary char [], and I try to avoid those in C++ code, if for nothing else but avoiding some arbitrary buffer size.

How to get only first words from several C++ strings?

I have several C++ strings with some words. I need to get the first word from every string. Then I have to put all of them into a char array. How can I do it?
Here is one way of doing it...
// SO2913562.cpp
//
#include <iostream>
#include <sstream>
using namespace std;
void getHeadWords(const char *input[]
, unsigned numStrings
, char *outBuf
, unsigned outBufSize)
{
string outStr = "";
for(unsigned i = 0; i<numStrings; i++)
{
stringstream ss(stringstream::in|stringstream::out);
ss<<input[i];
string word;
ss>>word;
outStr += word;
if(i < numStrings-1)
outStr += " ";
}
if(outBufSize < outStr.size() + 1)//Accomodate the null terminator.
//strncpy omits the null terminator if outStr is of the exact same
//length as outBufSize
throw out_of_range("Output buffer too small");
strncpy(outBuf, outStr.c_str(), outBufSize);
}
int main ()
{
const char *lines[] = {
"first sentence"
, "second sentence"
, "third sentence"
};
char outBuf[1024];
getHeadWords(lines, _countof(lines), outBuf, sizeof(outBuf));
cout<<outBuf<<endl;
return 0;
}
But note the above code has marginal error checking and may have security flaws. And needless to say my C++ is a bit rusty. Cheers.
I'll assume it's homework, so here is a general description:
First, you need to allocate enough space in your char array. In homework, you are usually told the maximum size. That maximum has to be enough for all the first words.
Now, you need to have an index for the insertion point in that array. Start it at zero.
Now go over your strings in order. In each, move an index forward from 0 until you see a \0 or a space (or other delimiter. Insert the character at the insertion point in the result array and increase that index by 1.
If you have encountered a space or a \0, you've found your first word. If you were on the last string, insert a \0 at the insertion point and you're done. If not, insert a space and move to the next string.
what compiler are you using?
converting to a chararray is the first thing to look for.
after done that, you can easily step through your array (and look for spaces)
something like this:
while (oldarray[i++] != ' ')
yournewarray[j++];
i think you gotta figure out the rest yourself, since this looks like some homework for school :)
Assuming this is homework, and that when you say "strings" you mean simple null-delimited arrays of char (and not std::string):
define your strings
define your resulting char array
for each string
find the offset of the first char that is not in the first word
append that many bytes of the string to the result array
If this is not homework, give us a little code to start with and we'll fill in the blanks.