У меня есть программа c, которая обнаруживает палиндром. Он также обнаруживает палиндромы с пробелами. Он возвращает -1, если строка пустая, 1, если это палиндром, и 0 в противном случае. Вот код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int pal(char *str){
if (str[0] == '\0'){
return -1;
}else{
size_t i = 0;
size_t j = strlen(str) - 1;
while(*(str + i) != '\0'){
if (*(str + i) == ' '){
i++;
continue;
}else if (*(str + j) == ' '){
j--;
continue;
}else{
if (*(str + i) != *(str + j)){
return 0;
}
}
i++;
j--;
}
return 1;
}
}
int main(){
char *str = "a man a plan a canal panama";
printf("%d", pal(str));
printf("\n");
return 0;
}
Когда я скомпилировал и запустил эту программу на своем локальном компьютере, она работала нормально. Но когда я загрузил его в вопрос INGInious моего курса CS (INGInious — это платформа, на которой люди могут загружать свои ответы по определенной теме, и система просматривает их), это вызывает ошибку сегментации. Есть ли какой-либо сценарий, который может привести к SegFault, о котором я не знаю?
*(str + i) то же самое, что и str[i], что намного легче читать.
@ Феликс, это не изменено.
Ваш j неконтролируемо уменьшается. Если он становится равным 0, вы теряете размер size_t (и он становится огромным).
Если тестовая строка начинается с пробела, то у элемента управления j проблемы. Но он компилируется и работает на MSVC без каких-либо проблем, и я не вижу никакой другой проблемы (кроме его эффективности - он должен остановиться на середине).
Это хороший момент, знает ли OP тестовую строку, вызвавшую сбой?
код имеет неопределенное поведение, если платформа, на которую вы загружаете свой код, тестирует str, будучи NULL...





В цикле ниже:
while(*(str + i) != '\0'){
if (*(str + i) == ' '){
i++;
continue;
}else if (*(str + j) == ' '){
j--;
continue;
}else{
if (*(str + i) != *(str + j)){
return 0;
}
}
i++;
j--;
}
Когда *(str + i) == '\0', это должно быть i == strlen(str) и j == -1 (если в строке нет пробела. В противном случае я не уверен), и это может быть проблемой. Но опять же, я действительно не вижу, чтобы вы не получили доступ str за пределы досягаемости. Вместо этого я бы предложил сделать это, чтобы вашему циклу было легче увидеть условие завершения:
while(i < j){
// ...
}
Как я уже сказал в своих комментариях, вы не контролируете значение j, и из-за этого ваш код может потенциально демонстрировать неопределенное поведение — когда j становится 0, но вы продолжаете его уменьшать, оно зацикливается и становится максимальным значением типа size_t (довольно впечатляющее число на современной платформе).
Этого не происходит с предоставленной вами строкой, но я полагаю, что ваша тестовая платформа проверяет ее на другой строке (это единственное объяснение сбоя, которое у меня есть).
Например, ваш код будет подвергаться неопределенному поведению в следующей строке: "a bcd"
Ваш код слишком сложен.
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
bool is_palindrome(char const *str)
{
size_t length = strlen(str);
for (char const *front = str, *back = str + length - 1; front != back; ++front, --back) {
while (isspace((char unsigned) *front) && front != str + length - 1)
++front;
while (isspace((char unsigned) *back) && back != str)
--back;
if (front == back)
break;
if (*front != *back)
return false;
}
return true;
}
int main(void)
{
char const *foo = "a man a plan a canal panama";
printf("%d\n", is_palindrome(foo));
char const *bar = "hello";
printf("%d\n", is_palindrome(bar));
}
1
0
Этот код трудно читать, но я бы поставил на доступ где-то за пределами границ.