问题
I am working on a plugin in C
for a game emulator, where I would like to remove all spaces from chat message before checking if the input messages contain any website urls.
So, I have this function like this to deblank (remove spaces from input message):
char* deblank(char* input) {
int i, j;
char *output = input;
for (i = 0, j = 0; i < strlen(input); i++, j++) {
if (input[i] != ' ')
output[j] = input[i];
else
j--;
}
output[j] = 0;
return output;
}
I use it in my plugin hook like this:
bool my_pc_process_chat_message(bool retVal___, struct map_session_data *sd, const char *message) {
if (retVal___ == true) {
char* check_message = deblank(message);
bool url_detected = (stristr(check_message, "://") || stristr(check_message, "www.") || stristr(check_message, "vvvvvv.") || stristr(check_message, "wvvw."));
if (!url_detected) {
int len = sizeof(tld_list) / sizeof(tld_list[0]);
int i;
for (i = 0; i < len; ++i) {
if (stristr(check_message, tld_list[i])) {
url_detected = true;
break;
}
}
}
if (url_detected) {
clif->messagecolor_self(sd->fd, COLOR_RED, "Possible GM Impersonation Detected - you cannot type website URLs in chat.");
return false;
}
}
return retVal___;
}
The above works, but there's a side-effect. What seems to be happening is that the input message is getting modified and all spaces from the message being removed, when it doesn't contain any website urls.
For example, if I typed:
Go to www.some-domain.com
The above get's blocked, So does this (when players try to be clever and use spaces):
w w w . s o m e - d o m a i n . c o m
However, when you type a normal message that doesn't contain any website urls like this:
Hello, how are you?
It's getting turned into the following:
Hello,howareyou?
This is because of this line: char* check_message = deblank(message);
The deblank function appears to be modifying the original message. I thought the function would return a new copy of the orignal message, without spaces.
Is there a way I can make a temporary copy of the original input message
, remove spaces from that, before doing my check?
Also, how do you clear allocated memory to the temp copy of the orignal input? I don't want this to linger around. Or does C automatically clears that temp char array once the code finishes it's execution in the scope?
回答1:
No, you can't actually do that.
There are two solutions: - Loop the string a first time to count how many non-space characters there are, so you know how much you need to allocate.
int count_not_empty(const char *str)
{
int n = 0;
for (; *str; ++str) {
if (*str != ' ') n++;
}
return n + 1; // the +1 is for the nulbyte at the end
}
- Allocate a string as big as the one you want to trim, and pad with nulbytes at the end.
i.e.
char *copy_not_empty(const char *str)
{
size_t i;
size_t j;
char *new = malloc(strlen(str) + 1);
for (i = j = 0; i < strlen(str); ++i)
{
if (str[i] != ' ')
new[j++] = str[i];
}
for (; j <= i; j++)
new[j] = 0; // pad with nulbytes
return new;
}
回答2:
Code broke the contract.
const char *message
points to data that should be not modified. deblank(message)
attempted to modified. it --> undefined behavior.
bool my_pc_process_chat_message(..., const char *message) {
if (retVal___ == true) {
char* check_message = deblank(message);
A properly warning enabled compiler would warn about this - saves you time.
For more detail and ideas, post the calling code to my_pc_process_chat_message()
.
来源:https://stackoverflow.com/questions/38543918/remove-spaces-from-char-array-in-c