2014-09-03 3 views
0

Итак, это мой первый пост, и я постараюсь быть настолько конкретным, насколько могу. я должен сделать программу для моей школы, которая говорит:сбой программ при закрытии

Сначала написать функцию, которая получает символ и возвращает:

  1. Тот же характер, если это верхний регистр букв.
  2. Письмо в верхнем регистре, если это нижний регистр.
  3. Обратная косая черта ('\'), если это число.
  4. Звездочка ('*') в любом другом случае.

Затем, используя вашу функцию, создайте программу, которая получит строку и перепечатает ее после ее изменения функцией. Он должен продолжать запрашивать новую строку, пока пользователь не наберет «QUIT», который в этом случае напечатает «Bye!». и затем уйти.

Вот мой код:

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

char fnChange(char c) 
{ 
    if (c > 'a'-1 && c < 'z'+1) 
      c = c - 32; 
    else if (c > '0'-1 && c < '9'+1) 
      c = '\\' ; 
    else if (c > 'A'-1 && c < 'Z'+1) 
      c = c; 
    else 
      c = '*'; 
    return c; 
} 


int main() 
{ 
    int i, refPoint; 
    char *str = (char*)malloc(10); 
    //without the next one, the program crashes after 3 repeats. 
    refPoint = str; 
    while (1==1) {    
     printf("Give a string: "); 
     str = refPoint;//same as the comment above. 
     free(str); 
     scanf("%s",str); 
     if (*str == 'Q' && *(str+1) == 'U' && *(str+2) == 'I' && *(str+3) == 'T') { 
      // why won't if (str == 'QUIT') work? 
      free(str); 
      printf("Bye!");  //after printing "Bye!", it crashes. 
      system("pause"); //it also crashes if i terminate with ctrl+c. 
      exit(EXIT_SUCCESS); //or just closing it with [x]. 
     }  
     printf("The string becomes: "); 
     while (*str != '\0') { 
      putchar(fnChange(*str)); 
      str++; 
     } 
     printf("\n"); 
    } 
} 
+2

'str = refPoint' ????? –

+1

'free (str)', а затем 'scanf ("% s ", str)' ????? Что именно вы ожидаете? –

+0

Небольшая точка (есть * реальные проблемы * с вашим кодом, см. Ответ Йоахима ниже), вместо 'c> 'a'-1' вы действительно должны написать' c> =' a''. Или, еще лучше, просто используйте ['islower()'] (http://linux.die.net/man/3/islower). – unwind

ответ

1

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

Вы free str, а затем выполните сканирование в него. Как только вы освободите память, он больше не доступен для использования.

Тогда сканирование f: scanf("%s", str). Как только кто-то вводит строку из 10 или более символов в консоли, вы вводите области неопределенного поведения, поскольку память будет перезаписана.

Назначение str на refpoint и наоборот должно дать вам массу предупреждений компилятора. Одна из ваших переменных - int, другая - char *. На некоторых архитектурах указатель не будет вписываться в int, и ваша программа выйдет из строя, как только вы ее используете.

Ваши приращения цикла while str. Без (опасной) копии от refpoint вы в конце концов попытаетесь освободить указатель, который не был результатом malloc. Это неопределенное поведение и, скорее всего, сбой.

Попутно:

Пожалуйста, не бросайте результат malloc. Он возвращает void *, а на C вы можете назначить void * на что угодно, а ненужное литье уменьшает читаемость кода. Кастинг подразумевает, что вы делаете что-то необычное, а это не так.

Вы не можете сделать str == 'QUIT ', потому что компилятор C сравнивает адрес строки с - ну, последствия ввода QUIT зависят от компилятора. Это, возможно, сравнит его с символьным значением «Q». Даже с str == "QUIT" он будет сравнивать значение указателя str (т. Е. Адрес, возвращаемый malloc) с адресом строки «QUIT», который будет находиться там, где компоновщик предназначен для его хранения. C не выполняет строковых сравнений, для этого вам нужно использовать strcmp.

5
free(str); 
scanf("%s",str); 

Большого нет-нет там, вы не можете использовать динамически выделенную память после того, как вы освободили его. Кроме того, вы снова освободите его внутри цикла.

Выполнение этого действия является неопределенным. Это почти наверняка является причиной вашего краха.

Пара других вопросов. Вы можете использовать <= вместо <, чтобы сделать код более удобным для чтения, например, с:

if ((c >= 'a') && (c <= 'z')) ... 

Использование магические номера, как 32 почти всегда плохая идея. При условии, что вы используете кодировку, где буквы подряд (например, ASCII), вы можете сделать:

c = c - 'A' + 'a'; 

превратить заглавные буквы в нижнем регистре.

Что вы действительно следует делать, однако, использует toupper() и tolower()isupper() и islower(), а также, чтобы обнаружить случай), так как буквы не гарантированно быть смежными.

Выражение str == 'QUIT' не будет делать то, что вы думаете, потому что 'QUIT' не является строкой. Скорее это многобайтовый символьный символ. Однако, даже str == "QUIT" не будет делать то, что вы думаете, так как правильный способ сравнения строк в С:

if (strcmp (str, "QUIT") == 0) ... 
4

У вас есть несколько случаев undefined behavior в вашем коде.

Прежде всего, вы назначаете указатель на целочисленную переменную. Они не совсем совместимы (например, подумайте о том, что произойдет, если размер int составляет 32 бита, а размер указателя - 64 бита).

Затем вы освобождаете выделенный указатель прямо перед его использованием, тем самым записывая в нераспределенную память.

И позже вы вызываете free на том же указателе.

Смежные вопросы