NumberFormatException
? Это исключение указывается, что приложение попыталось преобразовать
string
в один из числовых типов, ноstring
не имеет соответствующего формата.В вашем случае, согласно вашей трассировке стека это исключение было выбрано
Integer.parseInt(String)
, что означает, что предоставленныйString
не содержит синтаксический анализinteger
. И все же, согласно трассировке стека, это связано с тем, что вы пытались разобратьString
« Ace of Clubs » как целое число, которое не может работать, поскольку оно не являетсяString
представлением целого числа.Как это исправить?
Самый простой и общий способ - уловить исключение
NumberFormatException
int value = -1; try { value = Integer.parseInt(myString); } catch (NumberFormatException e) { // The format was incorrect }
Он будет работать, но ловить исключение медленное, потому что ему нужно построить стек вызовов, чтобы создать
Exception
, что дорого, поэтому, если вы можете этого избежать. Кроме того, вам нужно будет правильно управлять исключением, что не всегда очевидно.Или вы можете использовать
regular expression
для проверки, еслиString
matches
сInteger
, но он довольно подвержен ошибкам, так как вы можете легко использовать неправильныйregular expression
.В вашем случае следует использовать более OO-подход вместо работы с
String
, для Например, вы могли бы использоватьclass
илиenum
для представления ваших карт вместо простогоString
, потому что это гораздо больше подвержено ошибкам, как вы уже заметили.Итак, если вы решили использовать выделенный класс для своей карты, ваш код может быть:
public class Card { private final Rank rank; private final Suit suit; public Card(final Rank rank, final Suit suit) { this.rank = rank; this.suit = suit; } public Rank getRank() { return this.rank; } public Suit getSuit() { return this.suit; } }
Для костюма и ранга карты мы можем использовать
enum
, поскольку существуют ограниченные количества существующих рангов и костюмов.public enum Rank { ACE(1), TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), HEIGHT(8), NINE(9), TEN(10), JACK(11), QUEEN(12), KING(13); private final int value; Rank(final int value) { this.value = value; } public int getValue() { return this.value; } } public enum Suit { SPADE, HEART, DIAMOND, CLUB }
Тогда
cards
будет массивомCard
вместо массиваString
и может быть инициализирован следующим образом :Rank[] ranks = Rank.values(); Suit[] suits = Suit.values(); Card[] cards = new Card[ranks.length * suits.length]; for (int i = 0; i < ranks.length; i++) { for (int j = 0; j < suits.length; j++) { cards[i * suits.length + j] = new Card(ranks[i], suits[j]); } }
Если вам нужно перетасовать свой массив карт, вы можете действовать следующим образом (обратите внимание, что если вы решили использовать
List
карт вместо массива, просто используйтеCollections.shuffle(list)
)List
allCards = Arrays.asList(cards); Collections.shuffle(allCards); allCards.toArray(cards); Тогда вы сможете напрямую получить доступ к значению вашей карты с помощью
cards[index].getRank().getValue()
, не рискуя получить исключение (кромеIndexOutOfBoundsException
, если вы не используете правильный индекс).
Это «неопределенное поведение», что означает, что на основе стандарта вы не можете предсказать, что произойдет, когда вы попробуете это. Он может делать разные вещи в зависимости от конкретной машины, компилятора и состояния программы.
В этом случае чаще всего произойдет то, что ответ будет «да». Переменная const или нет - это просто место в памяти, и вы можете нарушать правила константы и просто перезаписывать ее. (Конечно, это вызовет серьезную ошибку, если какая-то другая часть программы зависит от постоянных константных данных!) [/ G2]
Однако в некоторых случаях - чаще всего для данных const static
- компилятора могут помещать такие переменные в область памяти, доступную только для чтения. MSVC, например, обычно ставит константные статические ints в .text сегменте исполняемого файла, что означает, что операционная система будет вызывать ошибку защиты, если вы попытаетесь записать на нее, и программа выйдет из строя.
В какой-то другой комбинации компилятора и машины может произойти нечто совершенно другое. Единственное, что вы можете точно предсказать, это то, что этот шаблон будет раздражать тех, кто должен прочитать ваш код.
Плохая идея BAD.
Кроме того, поведение зависит от платформы и реализации. Если вы работаете на платформе, где константа хранится в незаписываемой памяти, это, очевидно, не сработает.
И, почему бы вы хотели этого? Либо обновите константу в своем источнике, либо сделайте ее переменной.
Вы не можете изменить значение константы с помощью указателя, указывающего на него. Этот тип указателя называется Pointer to a constant
.
Существует также другое понятие, называемое Constant Pointer
. Это означает, что, как только указатель указывает на ячейку памяти, вы не можете указывать на другое местоположение.
Он действительно работает с gcc. Это ему не понравилось:
test.c: 6: warning: присваивание отбрасывает квалификаторы из целевого типа указателя
blockquote>Но значение изменилось, когда казнены. Я не буду указывать на очевидное нет-нет ...
Здесь тип указателя p
- int*
, которому присваивается значение типа const int*
(&a
=> адрес переменной const int
).
Неявный бросок исключает константу, хотя gcc выдает предупреждение (обратите внимание, что это во многом зависит от реализации).
Поскольку указатель не объявлен как const
, значение может (g3), если указатель будет объявлен как const int* p = &a
, вы не сможете сделать *p = 70
.
Это неопределенное поведение. Доказательство:
/* program.c */
int main()
{
const int a = 12;
int* p;
p = &a;
*p = 70;
printf("%d\n", a);
return 0;
}
gcc program.c
и запустите его. Выход будет равен 70 (gcc 4.3)
Затем скомпилируйте его следующим образом:
gcc -O2 program.c
и запустите его. Выход будет 12. Когда он выполняет оптимизацию, компилятор предположительно загружает 12 в регистр и не утруждает себя повторной загрузкой, когда ему нужно получить доступ к a для printf, потому что он «знает», что не может измениться.
const
- UB. Причина, по которой это UB, заключается в том, что на практике трудно обеспечить логически правильное поведение без защиты памяти уровня ОС.
– JeremyP
18 September 2017 в 09:00
да, вы можете сделать это, используя такой код. но код не применяется, когда a
является глобальным (gcc-скомпилированная программа дала мне segmentation fault
.)
, вообще говоря, в любимом C, вы почти всегда можете найти что-нибудь, чтобы взломать вещи, которые не должны быть изменены или выставлены. const здесь является примером.
Но размышление о бедном парне (может быть, мне через 6 месяцев) поддерживает наш код, я часто предпочитаю не делать этого.
Этот код содержит нарушение ограничения :
const int a = 12;
int *p;
p = &a;
Нарушенное ограничение - C11 6.5.16.1/1 «Простое назначение»; если оба операнда являются указателями, то тип, на который указывает левый, должен иметь все определители типа, на который указывает справа. (И типы, sans qualifiers, должны быть совместимы).
Таким образом, ограничение нарушается, потому что &a
имеет тип const int *
, который имеет const
в качестве определителя; но этот определитель не отображается в типе p
, который является int *
.
Компилятор должен испустить диагностику и не может генерировать исполняемый файл. Поведение любого исполняемого файла полностью не определено, так как программа не соответствует правилам языка.
Модификация const
квалифицированного объекта через указатель вызывает неопределенное поведение, и таков результат. Скорее всего, это то, чего вы ожидаете, т.е. предыдущее значение не изменилось, если оно помещено в .text
и т. д.
a
все еще равно 12, а другие ведут себя так, как будто a
теперь составляет 70», что может быть или не быть «то, что вы ожидаете».
– caf
27 September 2010 в 08:38
Да, вы можете изменить значение постоянной переменной. Попробуйте этот код:
#include <stdio.h>
int main()
{
const int x=10;
int *p;
p=(int*)&x;
*p=12;
printf("%d",x);
}