Не могу понять, что это за функция и как она работает? Также что такое условие * p в цикле for? Чем он занимается?
char *uppercase(char *s)
{
for(char *p = s; *p; ++p)
{
if ('a' <= *p && *p <= 'z')
*p = *p - 32;
}
return s;
}
Я не могу назвать это как верхний регистр ("любая строка"), и этот char *uppercase меня смущает.
Нет видов функций. Это просто: функция
Строки в C — это char
массивы. Соглашение состоит в том, что существует сигнальное значение «конец строки», равное 0x00. *p;
— это способ остановки цикла при обнаружении сигнализатора EOS (т. е. при достижении конца строки). Он продолжает цикл, только если текущий персонаж не является часовым. *p;
это сокращение от *p != 0;
Стоит отметить, что вы можете передавать только имя массива, а не указатель на константную строку.
@Ron Как я могу передать постоянную строку?
@Bobamas Вы не можете передать указатель на постоянную строку в свою функцию, так как ваша функция изменяет данные, на которые указывает. Попытка изменить постоянную строку, на которую указывает указатель, является UB. Таким образом, передача указателя, определенного как char* c = "Hello World";
, является UB. Передача имени массива символов, определенного как char c[] = "Hello World";
, допустима.
@Bobamas I can call it like uppercase("any string")
- нет, нельзя. В этом примере вызывается Undefined Behavior
char *uppercase(char *s)
объявляет uppercase
функцией с параметром s
типа char *
, которая возвращает char *
. (char *
означает тип, который является указателем на char
объект в памяти.)
for(char *p = s; *p; ++p)
определяет char *
с именем p
и инициализирует его как s
. Итак, когда этот цикл начинается, p
указывает на то же место, на которое указывает s
. Второй элемент, *p
, говорит продолжать цикл до тех пор, пока *p
не равно нулю. (*p
— это char
, на который в данный момент указывает p
.) Третий элемент, ++p
, говорит об увеличении p
на единицу на каждой итерации. Это заставляет p
указывать на следующее char
в памяти.
if ('a' <= *p && *p <= 'z')
— это непереносимая проверка того, является ли p
строчной буквой. Стандарт C не гарантирует, что коды строчных букв от a
до z
находятся между значениями кодов a
и z
или что между ними нет других кодов. Правильный способ написать это if (islower((unsigned char) *p))
.
*p = *p - 32;
— плохой способ изменить код строчной буквы на код соответствующей прописной буквы. Это плохо, потому что он зависит от разницы между кодами этих букв, равной 32. Это особенность ASCII, но стандарт C не гарантирует этого. *p += 'A' - 'a';
было бы немного лучше написать это, но стандарт C предлагает лучший способ: *p = toupper(*p);
.
Эти islower
и toupper
функции объявлены в заголовке <ctype.h>
. (Примечание. Использование toupper
с символами, которые, как известно, не входят в базовый набор символов выполнения, требует преобразования его ввода в unsigned char
и учета того факта, что его выходное значение может переполнить char
. Поскольку этот исходный код применяет toupper
только к символам, которые уже известно, что это строчные буквы, которые входят в базовый набор символов выполнения, это не проблема.)
Таким образом, функция проверит каждый символ в строке, на которую указывает s
, и изменит все строчные буквы на прописные.
Omg Большое спасибо за это гладкое объяснение!! Если я хочу сделать эту функцию нулевой безопасной, достаточно ли if (*s == NULL){ return 1;}?
@Bobamas: если функция вызывается с нулевым аргументом, она должна объявить об ошибке (возможно, напечатать сообщение и выйти из программы, или вызвать какую-либо процедуру обработки ошибок, или запустить сигнал) и/или вернуть нулевой указатель. Он не должен возвращать 1. (Вы можете использовать return 0;
, чтобы вернуть нулевой указатель, или return (void *) 0;
, чтобы прояснить намерение, или return NULL;
, если включен подходящий заголовок.)
@Bobamas помните, что вы не можете использовать это так uppercase("hello world");
@P__JsupportswomeninPoland Есть ли решения для такого использования?
Вам нужно выделить новый массив символов для сохранения результата.
Я много думаю об этом, но не могу понять, как сохранить результат
статическая переменная, malloc
Тип указателя по-прежнему остается типом, в вашем случае — типом
char *
.