Еще один простой и глупый вопрос о строках C++

Я сделал такой набросок:

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600);

  char str1[64] = "test with spaces";
  char str2[32] = "test with spaces";

  Serial.println(str1);
  Serial.println(str2);

  if (str1 == str2) Serial.println("Equals");
  else Serial.println("Different");

  if (strcmp(str1, str2)) Serial.println("Equals");
  else Serial.println("Different");

// if (strcoll(str1, str2)) Serial.println("Equals"); // <-- это не скомпилируется для Arduino UNO { почему ??? }
// иначе Serial.println("Другой");

  if (memcmp(str1, str2, sizeof(str2))) Serial.println("Equals");
  else Serial.println("Different");

  if (areEqual(str1, str2)) Serial.println("Equals");
  else Serial.println("Different");

  strcpy(str1, "test+with+spaces");
  strcpy(str2, "test with spaces");

  Serial.println();
  Serial.println(str1);
  Serial.println(str2);

  if (str1 == str2) Serial.println("Equals");
  else Serial.println("Different");

  if (strcmp(str1, str2)) Serial.println("Equals");
  else Serial.println("Different");

  if (memcmp(str1, str2, sizeof(str2))) Serial.println("Equals");
  else Serial.println("Different");

  if (areEqual(str1, str2)) Serial.println("Equals");
  else Serial.println("Different");

  strcpy(str1, "test+with++++++++++++++++++++++++++++++++++++spaces");
  strcpy(str2, "test with spaces");

  Serial.println();
  Serial.println(str1);
  Serial.println(str2);

  if (str1 == str2) Serial.println("Equals");
  else Serial.println("Different");

  if (strcmp(str1, str2)) Serial.println("Equals");
  else Serial.println("Different");

  if (memcmp(str1, str2, sizeof(str2))) Serial.println("Equals");
  else Serial.println("Different");

  if (areEqual(str1, str2)) Serial.println("Equals");
  else Serial.println("Different");

}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:

}


bool areEqual(char* string1, char* string2) {
  return ((strlen(string1) == strlen(string2)) && (strstr(string1, string2)));
}

Что производит это:

test with spaces
test with spaces
Different
Different
Different
Equals

test+with+spaces
test with spaces
Different
Equals
Equals
Different

test+with++++++++++++++++++++++++++++++++++++spaces
test with spaces
Different
Equals
Equals
Different

Первое сравнение глупо (==), я знаю. Он сравнивает адрес указателя, а не самой строки. Я просто поместил его, чтобы показать, как трудно программисту, который говорит на другом языке, понять такие вещи.

Второе сравнение (strcmp), как сказано в ссылке, «Сравнивает строку C str1 со строкой C str2.», НЕТ, это не так. Они абсолютно одинаковы, за исключением их заранее заданного размера. Но строки равны как мне кажется.

Третье сравнение (strcoll) использует локаль для сравнения двух строк, но почему они говорят разные, когда они равны?

Четвертое сравнение (memcmp), учитывая два указателя на одну и ту же последовательность символов, почему написано "разные"?

Самая умопомрачительная часть заключается в том, что сравнение "работает", когда вы добавляете столько "+", сколько хотите, только к одной из строк. Разве знак "+" тоже не символ?

Очевидно, что я упускаю что-то действительно важное в строках в стиле C++, но осмелюсь спросить: что это такое?

Спасибо.

, 👍1

Обсуждение

Небольшое замечание по номенклатуре: строки вида char * называются "строками C" (будьте осторожны при поиске в гугле), строками с нулем или нулем в конце, поскольку они возникли в C. Напротив, строки C++ имеют тип std::строка. С ними сравнение с == работает так, как вы ожидаете: оно сравнивает строки, а не указатели., @Heinrich supports Monica


2 ответа


0

Есть еще одна функция сравнения строк, которая может вам помочь strncmp()

void setup(){
  Serial.begin(9600);
  char str1[64] = "test with spaces";
  char str2[32] = "test with spaces";
  if(strncmp(str1, str2, 64) == 0){
    Serial.println("strings match");
  }
  else{
    Serial.println("strings do not match");
  }
}

void loop(){}
,

5

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

strcmp – это компаратор с тремя состояниями, который возвращает отрицательное, нулевое или положительное значение. Для равных строк он возвращает ноль, что означает, что сравнение на равенство с strcmp обычно должно выглядеть следующим образом

if (strcmp(str1, str2) == 0) Serial.println("Equals");
else Serial.println("Different");

в то время как исходный код делает обратное.

Существует довольно распространенная некрасивая привычка писать такие сравнения, как

if (!strcmp(str1, str2)) Serial.println("Equals");
else Serial.println("Different");

(обратите внимание на применение оператора !). Он работает правильно, но имеет плохую читабельность. Избегай это. Для компараторов с тремя состояниями гораздо лучше явно указать сравнение с 0.

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

if (memcmp(str1, str2, sizeof str2) == 0) Serial.println("Equals");
else Serial.println("Different");

То же самое относится и к strcoll.

PS И на самом деле такие строки с завершающим нулем, представленные массивами char[], называются строками в стиле C, а не строками в стиле C++.

,

Уххх. Вы молодцы. В конце концов, вокруг строк не было никаких мистических облаков, все дело было в результатах функций. Спасибо., @MrCabana