我在用于简单替换加密的程序中使用以下方法。此方法专门用于删除加密/解密密钥中的重复字符。
该方法功能正常,程序的其余部分也是如此,它适用于我尝试过的99%的密钥。但是,当我将密钥<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown"> Services</a>
<ul class="dropdown-menu services-dropdown" role="menu">
@forelse(App\Model\Service::all() as $service)
<li class="dropdown-submenu">
<a href="{{ url('services/'.$service->slug) }}">{{ $service->title }}</a>
<ul class="dropdown-menu sub-services">
@foreach(App\Model\SubService::where('service_id', '=',$service->id)->get()) as $subservice)
<li>
<a href="{{ url('sub-services/'.$subservice->slug) }}">{{ $subservice->title }}</a>
</li>
@endforeach
</ul>
</li>
@empty
@endforelse
</ul>
</li>
或任何按相同字母组成的密钥(例如"goodmorning"
)传递给它时,它会失败。此外,包含比"dggimnnooor"
更多字符的键以及具有较少字符的键。
我使用相同的参数通过"goodmorning"
运行可执行文件并且它可以正常运行。我在运行CentOS的机器上克隆了我的存储库,它按原样运行。
但是我在编译时没有收到任何警告或错误。
lldb
每个请求:如果将//setting the key in main method
char * key;
key = removeDuplicates(argv[2]);
//return 1 if char in word
int targetFound(char * charArr, int num, char target){
int found = 0;
if(strchr(charArr,target))
found = 1;
return found;
}
//remove duplicate chars
char * removeDuplicates(char * word){
char * result;
int len = strlen(word);
result = malloc (len * sizeof(char));
if (result == NULL)
errorHandler(2);
char ch;
int i;
int j;
for( i = 0, j = 0; i < len; i++){
ch = word[i];
if(!targetFound(result, i, ch)){
result[j] = ch;
j++;
}
}
return result;
}
传递给此函数,则生成的字符串将为"feather"
。
答案 0 :(得分:4)
正如R Sahu已经说过的那样,您没有使用NUL
字符终止字符串。现在我不打算解释为什么你需要这样做,但是你总是需要用NUL
字符终止你的字符串,'\0'
。如果您想知道原因,head over here可以获得一个很好的解释。但是,这不是您的代码唯一的问题。
主要问题是您要调用的函数strchr
,以确定您的result
是否已包含某些字符,希望您传递NUL
已终止的字符串,但您的变量不会NUL
终止,因为您会不断为其添加字符。
要解决您的问题,我建议您改用地图。映射您已使用过的所有字符,如果它们不在地图中,则将它们添加到地图和结果中。这更简单(无需调用strchr
或任何其他函数),速度更快(无需每次都扫描所有字符串),最重要的是正确。
这是一个简单的解决方案:
char *removeDuplicates(char *word){
char *result, *map, ch;
int i, j;
map = calloc(256, 1);
if (map == NULL)
// Maybe you want some other number here?
errorHandler(2);
// Add one char for the NUL terminator:
result = malloc(strlen(word) + 1);
if (result == NULL)
errorHandler(2);
for(i = 0, j = 0; word[i] != '\0'; i++) {
ch = word[i];
// Check if you already saw this character:
if(map[(size_t)ch] == 0) {
// If not, add it to the map:
map[(size_t)ch] = 1;
// And to your result string:
result[j] = ch;
j++;
}
}
// Correctly NUL terminate the new string;
result[j] = '\0';
return result;
}
为什么这适用于其他计算机,而不适用于您的计算机?
您是未定义行为的受害者。不同系统上的不同编译器以不同方式处理未定义的行为例如,GCC可能决定在这种特定情况下不做任何事情,并使strchr
只是继续在内存中搜索,直到找到'\0'
字符,这正是发生的事情。你的程序一直在搜索NUL
终结符并且永远不会停止,因为谁知道你的字符串之后'\0'
在内存中的位置?这既危险又不正确,因为程序没有在为其保留的内存中读取,因此,例如,另一个编译器可能决定停止搜索,并给出正确的结果。然而, 这是理所当然的事情,你应该总是避免未定义的行为。
答案 1 :(得分:1)
我在你的代码中看到了几个问题:
因此,您的程序有不确定的行为。
更改
result = malloc (len * sizeof(char));
到
result = malloc (len+1); // No need for sizeof(char)
在函数返回之前添加以下内容。
result[j] = '\0';
另一个问题,主要问题是,您在strchr
上使用result
,当您致电targetFound
时,这不是空终止字符串。这也导致了未定义的行为。你需要使用:
char * removeDuplicates(char * word){
char * result;
int len = strlen(word);
result = malloc (len+1);
if (result == NULL)
{
errorHandler(2);
}
char ch;
int i;
int j;
// Make result an empty string.
result[0] = '\0';
for( i = 0, j = 0; i < len; i++){
ch = word[i];
if(!targetFound(result, i, ch)){
result[j] = ch;
j++;
// Null terminate again so that next call to targetFound()
// will work.
result[j] = '\0';
}
}
return result;
}
第二种选择是不在strchr
中使用targetFound
。请改用num
并实现等效功能。
int targetFound(char * charArr, int num, char target)
{
for ( int i = 0; i < num; ++i )
{
if ( charArr[i] == target )
{
return 1;
}
}
return 0;
}
这样可以避免将空字符分配给result
这么多次。您只需要在结尾处终止result
。
char * removeDuplicates(char * word){
char * result;
int len = strlen(word);
result = malloc (len+1);
if (result == NULL)
{
errorHandler(2);
}
char ch;
int i;
int j;
for( i = 0, j = 0; i < len; i++){
ch = word[i];
if(!targetFound(result, i, ch)){
result[j] = ch;
j++;
}
}
result[j] = '\0';
return result;
}