C/C++

В чём причина? Понторезов с очень высшим образованием слушать не буду. Только тех, кто практикует работу с указателями вС++

Char *Text= " 110abcde -12 fghi239jklmn1opqr-20stuvw509xyz 34 "; char *EndStr;
int len= *Text - *EndStr; printf("Длина текста %d\n", len);

В КОДБЛОК работает, а в VS не работает. Причина? Не знаю
Хотя вычесть адрес памяти указателя символьного и указатель символьного есть или должно быть просто число вполне вычисляемое и пригодное для инт в неявном преобразовании
Хизри Закиев
Хизри Закиев
21 700
В С++ при компилировании в Release память инициализируется нулями, для разыменованного указателя на char это равносильно символу конца строки. Тогда код..

int len= *Text - *EndStr;

...вернёт целое значение первого символа в строке Text. Если длина строки совпадает со значением символа, то ошибочно можно принять такой код как валидный. У вас там пробел, значит printf выводит 32, а сколько должно? Не 49 ли?
Руслан Выговский
Руслан Выговский
56 058
Лучший ответ
Руслан Выговский Как только что выяснил, компилятор от Майкрософт больше не инициализирует память нулями в Release, сейчас там мусор! А в Debug возвращает -52, что соответствует 0xCC и это правильно.

Так что настоятельно рекомендую не использовать неинициализированные переменные. Это значит, что их следует инициализировать значениями по умолчанию при объявлении. Вот так так подсказывает IntelliSense теперь это делать, она спрашивает: «Добавить инициализатор» и если вы соглашаетесь, то код из такого...

char box[12];
int x;

...изменяет на такой...

char box[12]{};
int x = 0;
Дмитрий Гречишников Даже если предположить, что компилятор инициализирует память нулями, то переменная EndText будет содержать nullptr и её разыменование тоже даст неопределённый результат.
То, что это сработало в Code::Blocks - абсолютная случайность.

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

Char *Text= " 110abcde -12 fghi239jklmn1opqr-20stuvw509xyz 34 ";
ты создаёшь переменную Text и заносишь в неё адрес начала строки " 110abcde -12 fghi239jklmn1opqr-20stuvw509xyz 34 ".

char *EndStr;
ты создаёшь переменную EndStr и НИЧЕГО в неё не заносишь - в EndStr находится никому неизвестный мусор, указывающий неизвестно куда.

В той книге, на которую ты ссылаешься в комментариях к предыдущему ответу (совершенно искажая смысл написанного - в силу собственного непонимания), было:
char *EndStr = "";

int len= *Text - *EndStr;
*Text - *EndStr - это в точности тоже самое, что и Text[0] - EndStr[0] - ты берёшь значение байта по адресу, который находится в Text (т. е. код символа 'пробел'), и вычитаешь из него значение байта по адресу, который находится EndStr. Но EndStr содержит неизвестно что, потому и будет взято неизвестно что или программа просто вырубится - если этот "адрес" указывает в неположенное место.

Опять же, в той книге было:
int len = EndStr - Text;

Только не стоит надеяться, что получится: это грязный хак тех доисторических времён, когда компиляторы не умели качественно оптимизировать код. В современных же реалиях это эталонный UB.
*** Павел ***
80 788
Хизри Закиев char* EndStr = ""; эту конструкцию VS отмечает как крамольную
Хизри Закиев В общем и целом, как примет компилятор, так и правильно. Тогда объявите единственно правильным компилятором С++ VS 2019, у которого я слышал некоторые ранние версии тоже нуждаются в доработке
Длина строки в char* считается примитивным циклом, вот так:

int size=0;
while(*Text!='\0')
{
Text++; size++;
}
printf("\n Lenth of Text =%d",size);

А int len= *Text - *EndStr не выдаёт ошибку, так как не инициализированная переменная char* EndStr как указатель
имеет нулевое значение 0x0. Если ей присвоить значение, то
int len= *Text - *EndStr выдаст ошибку сразу. А до этого вычитался ноль.
Дмитрий Гречишников Или просто через ::strlen
Руслан Выговский Или так))

const char* s = "Hello world!";
const char* p = s;
while (*(++p));
printf("Length: %i\n", p - s);
Николай Лазакович вот пример двух вариантов поиска, 'р' не нашли, '_' нашли:
char *text2="text_русские буквы";
char* st=strchr(text2, 'p');
printf("\nАдрес = %s",st);

char* st=strchr(text2, '_');
printf("\n Адрес = %s",st);
EndStr не инициализирован, т. е. в нём может быть записан абсолютно любой мусор. Следовательно, значение len тоже не определено, и это код может работать вообще как угодно и в MinGW/GCC, и в MSVC.

А, ну и разумеется, *Text - это разыменование Text, т. е. получение того, что лежит по указателю. Сам адрес указателя - это в данном случае просто Text.
Михаил Перов
Михаил Перов
36 956
Хизри Закиев Стоп! Инициализация и выделение памяти АБСОЛЮТНО разные действия. Сначала указатель формируется в виде АДРЕСА памяти на EndStr, а потом уже туда может быть что-то запишут. По-любому резервируют память типа DUP (?) я так понимаю
Хизри Закиев Я где-то в книгах по с++ видел именно такой приём работы. Скажи умники стандартами уродуют язык. В числе лидеров VS (((((((
Хизри Закиев Тем более при выделении памяти символьные строки располагаются компилятором по возможности ПОДРЯД, а указатели в таблице/области переменных в виде адресов/ссылок на участки памяти. WTF может понятнее спросить у иностранцев ))
Из всего вышесказанного, могу добавить только, что разность указателей - это не int, а ptr_diff. А длина чего-либо - это size_t

И ещё. Под WinAPI нет UTF-8, там упрощённый UTF-16. А под C Runtime Library, напротив он есть. Так что, смешивать WinAPI и стандартный Си не рекомендуется. Если пишешь TEXT(""), тогда уж пиши и TCHAR* или LPTSTR, что синонимы по-сути.

P.S. И да, я не получал высшее образование.
Хизри Закиев молодец, что не получал и не покупал тем более, но в VS принимает только TEXT(""); уже пробовал все варианты
Сергей Поскребышев На начальном этапе я бы не заморачивался всем этим. Просто программируй и всё. Стандарты изучишь потом.
У вас указатель не инициализирован.

* - оператор разыменовывания указателя - получение значения, хранящегося по адресу, на который указывает указатель.

*Text - значение по адресу в Text
*EndStr - значение по адресу в EndStr, который не определен.

Разыменовывание неопределенного указателя - UB

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

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

==============
ТЕОРИЯ

Указатель - переменная хранящая адрес участка памяти.
Размер указателя зависит от архитектуры, на которой скомпилирован исполняемый файл.
Объявление указателя char* somePtr; // указатель на переменную типа char
По умолчанию указатель не инициализирован.
Оператор взятия адреса & возвращает указатель.
Указателю можно присвоить конкретный адрес somePtr = &someChar;
Указателю можно присвоить нулевое значение somePtr = nullptr; // C++11
Т. к. указатель - переменная, то можно определить указатель на указатель.
Т. е. char** somePtrPtr = &somePtr; // указатель на переменную типа char* - т. е. на указатель на переменную типа char

Действия с указателями:
Разыменовывание - получение значения, хранящегося по адресу.
char charFromPtr = *somePtr;

Над указателями можно выполнять унарные операции: инкремент и декремент. При выполнении операций ++ и — значение указателя увеличивается или уменьшается на длину типа, на который ссылается используемый указатель. (Можно использовать для перехода к следующему/предыдущему элементам массива).

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

Значения двух указателей на одинаковые типы можно сравнивать в операциях ==, !=, <, <=",">, >=;
Bazarbay Zhusupbaev
Bazarbay Zhusupbaev
17 671
Хизри Закиев неполная информация. Указатели можно складывать между собой и с числовыми константами. В общем как нахреначили компилятор, так и программы колбают. Ура