Создание заглавных букв без указателей

Я пытаюсь написать функцию в верхнем регистре, которая преобразует все строчные символы в строке в их эквиваленты в верхнем регистре.

Однако я получаю ошибку Bus 10 в своем коде. Я знаю, что строковые литералы не могут быть изменены в C; поэтому я не уверен, что это правильный подход.

Мой код ниже:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

int uppercase(char source[])
{
 int i;

 for(i=0; i<=strlen(source); ++i)
    if (source[i]>= 'a' && source[i]<= 'z')
        source[i]= source[i]-'a' +'A';
    else 
        source[i]=source[i];
}

int main(){
    uppercase("cold");

    return 0;
}

В идеале эта функция должна возвращать COLD. Я полагаю, что ошибка заключается во всем моем операторе if.


person Rohit Tigga    schedule 21.12.2013    source источник
comment
Вы сами ответили на свой вопрос. И что вы имеете в виду под возвратом?   -  person Kerrek SB    schedule 22.12.2013
comment
И в чем смысл source[i] = source[i]??   -  person Kerrek SB    schedule 22.12.2013
comment
Извините, я должен был быть яснее. Я не знаю, как исправить ошибку в этом случае. Смысл в том, чтобы ничего не менять. Я думаю, это лишнее?   -  person Rohit Tigga    schedule 22.12.2013
comment
Я думаю, вы также должны включить функцию/метод uppercase().   -  person Doro    schedule 22.12.2013
comment
Спасибо, Чукс. Но не могли бы вы дать объяснение?   -  person Rohit Tigga    schedule 22.12.2013
comment
@XiJiaopin Другие хорошо обеспечены.   -  person chux - Reinstate Monica    schedule 22.12.2013


Ответы (2)


Причина сбоя заключается в том, что ваш код изменяет строковый литерал. Символы внутри строковых литералов помещаются в защищенную область памяти и поэтому не могут быть изменены: это поведение undefined.

Замените это

uppercase("cold");

с этим:

char cold[] = "cold";
uppercase(cold);

Теперь символы строки помещаются в редактируемую область памяти, что позволяет вносить изменения по мере необходимости.

person Sergey Kalinichenko    schedule 21.12.2013
comment
@XiJiaopin: Добро пожаловать в SO! Ваш статус предполагает, что вы еще не прочитали страницу О; пожалуйста, сделайте это скорее. А пока прочитайте Кто-то ответил на мой вопрос! Что теперь делать? и подумайте о том, чтобы принять один из ответов на ваши вопросы. - person Jongware; 22.12.2013

Вы абсолютно работаете с указателями, даже не подозревая об этом.

В вашем определении функции

int uppercase(char source[])

char source[] рассматривается компилятором как указатель на char (char *source)

Итак, при передаче строкового литерала в uppercase() вы просто передаете его адрес. Затем в вашей функции вы пытаетесь изменить ее, что приводит к неопределенному поведению.

Также вы не можете вернуть весь массив, поэтому вы просто возвращаете указатель на него.

char *uppercase(char source[])
{
     int i;
     size_t len = strlen(source);
     char *tmp;
     tmp = malloc(len+1);
     if (tmp!=NULL){
         memcpy(tmp, source, len+1);
         for(i=0; i<len; ++i){
            if (tmp[i]>= 'a' && tmp[i]<= 'z'){
                tmp[i]= tmp[i]-'a' +'A';
            }
        }
    }
    return tmp;
}

Затем:

int main(){
    char *str = uppercase("cold");
    printf("%s", str);
    free(str);

    return 0;
}

Вы заполняете код: http://ideone.com/BJHDIF

person rullof    schedule 21.12.2013
comment
Вам нужно выделить место для нулевого терминатора и действительно следует добавить free(tmp); в main - person simonc; 22.12.2013
comment
Разве strlen не включает нулевой терминатор? зачем освобождать tmp, это приведет к его потере, потому что функция возвращает его. - person rullof; 22.12.2013
comment
Нет, strlen не включает терминатор. Вы не можете вызвать free для динамически выделенного возврата из uppercase, пока не закончите с ним, но в какой-то момент вы должны освободить его. Ваше предложение приводит к утечке этой памяти; не имеет большого значения в этой крошечной программе, но очень плохой совет для программирования в целом. - person simonc; 22.12.2013
comment
Вы забыли нулевой терминатор :) - person rullof; 22.12.2013
comment
Я так не думаю - malloc(len+1) выделяет для него место и strcpy копирует. Я упустил из виду, что цикл завершился на один символ раньше — теперь это исправлено. - person simonc; 22.12.2013
comment
Поскольку у вас уже есть длина, использование strcpy является излишним: используйте memcpy(tmp, source, len + 1) (вместо этого я бы скопировал строку в цикле). Тип возвращаемого значения strlen()size_t, а не int, то же самое для типа аргумента malloc. Вы также делаете len = strlen(tmp);, хотя здесь вы имели в виду source, а не tmp. И вам действительно следует проверить, вернул ли malloc NULL. - person ZyX; 22.12.2013
comment
@ZyX, как проверить, вернул ли malloc NULL, и почему memcpy лучше, чем strcpy - person rullof; 22.12.2013
comment
@rullof 1.?! Как проверить, является ли указатель NULL? Используйте 1_. 2. strcpy работает со строками неизвестной длины. т.е. он должен работать со строками таким образом, чтобы он не обращался к памяти после нулевого байта. memcpy копирует непрерывный блок памяти с заданной начальной позицией и длиной. Ему не нужно проверять, содержит ли данный фрагмент какой-либо определенный байт, а также ему не нужно обрабатывать память с определенной позиции (т.е. начала фрагмента) и в заданном направлении (т.е. от начала до конца), что означает, что в реализации memcpy возможны дополнительные оптимизации. . - person ZyX; 22.12.2013
comment
Примечание о malloc: он возвращает NULL, если нет памяти. В этом случае можно ожидать, что ваше приложение попытается освободить часть памяти, но, скорее всего, просто вылетит с жалобой на нехватку памяти (если вы не добавите эту проверку, оно вылетит без понятного сообщения, потому что вы пытаетесь записать по адресу 0x0 (NULL )). - person ZyX; 22.12.2013
comment
!==? Это не JavaScript. Также можно отбросить else ветку: если tmp == NULL разницы между return NULL и return tmp точно нет. И main() не волнует случай, когда uppercase() функция вернула NULL. - person ZyX; 22.12.2013
comment
Угг снова промахнулся. я должен пойти на самоубийство - person rullof; 22.12.2013
comment
Главное, что мне не нравится в C, это то, что иногда более половины кода занимается обработкой ошибок. Более половины обработки ошибок заключается в передаче ошибок от вызываемого объекта к вызывающему. - person ZyX; 22.12.2013