#c
#c
Вопрос:
char purl[1024];
unsigned char * puMember;
unsigned char uMember;
puMember = amp;uMember;
unsigned char * pMember;
unsigned char Member;
pMember = amp;Member;
printf("member: %sn",pMember);
printf("username :%sn",puMember);
sprintf(purl, "Username: %s %s",puMember,pMember);
printf("URL:%sn",purl);
printf("member: %sn",puMember);
printf("username :%sn",pMember);
Вывод
member: 12345678
username :User1
URL: username: cUser1 ser1
member: User1
username :ser1
Я не понимаю, почему sprintf портит мои указатели после их выполнения.
У pMember есть 12345678, а у puMember есть User1, я пытаюсь отформатировать их в строку (purl), но, похоже, sprintf их путает :/
Любая помощь, как я мог бы это сделать?
Комментарии:
1. Как выглядят определения этих переменных? Я подозреваю, что вы переполняетесь
purl
.2. нам нужны определения
pMember
,puMember
,purl
; и если это не составит особого трудаpUserID
иpMemberID
. Спасибо3. добавлено немного больше информации, надеюсь, это поможет
4. Стилистический комментарий — не используйте временные обозначения для указателей на переменные, за этим трудно уследить. Используйте
amp;var
вместо этого.
Ответ №1:
Ваш код очень странный — если pMember
и puMember
указывают на отдельные символы, почему printf
они в виде строки, завершающейся mull? Он будет печатать что угодно, пока не найдет null в памяти.
Аналогично, sprintf
будет продолжать считывать память после символов Member
и uMember
и заполняться purl
— в зависимости от того, когда он найдет нулевой байт в памяти.
Использование snprintf
вместо printf
позволит избежать переполнения буфера, но чего именно вы пытаетесь достичь?
Комментарии:
1. Ну, я печатаю их, потому что я заполнил оба из них значением, а последний символ [] равен », так что это printf без каких-либо проблем. Я пытаюсь получить purl в виде строки, равной «Username: 123456789, User1», передавая 2 переменные для создания такого типа строки, поскольку это все меняет.
2.
Member
иuMember
содержит только 1 символ. Как вы можете «заполнить их», плюс добавить завершающий null? Что вы на самом деле делаете, так это перезаписываете смежную память.3. Я понимаю, что ты имеешь в виду! Я редактировал указатель и добавлял символы и не понимал, что это не выделенная мне память, а запись в другом месте. Спасибо
Ответ №2:
char purl[1024];
unsigned char * puMember;
unsigned char uMember;
uMember
имеет пробел для 1 символа; 'F'
или '4'
или ''
puMember = amp;uMember;
puMember
указывает на этот символ. И только этот символ: размер объекта составляет 1 байт.
unsigned char * pMember;
unsigned char Member;
Member
есть пробел для 1 символа
pMember = amp;Member;
pMember
указывает на 1 символ.
printf("member: %sn",pMember);
Нет, нет, нет. pMember не указывает на «строку». Вы вызвали неопределенное поведение: может произойти все, что угодно
printf("username :%sn",puMember);
Нет, нет, нет. puMember не указывает на «строку». Вы вызвали неопределенное поведение: может произойти все, что угодно
sprintf(purl, "Username: %s %s",puMember,pMember);
Нет, нет, нет. puMember и pMember не указывают на «string»ы. Вы вызвали неопределенное поведение: может произойти все, что угодно
printf("URL:%sn",purl);
printf("member: %sn",puMember);
printf("username :%sn",pMember);
Нет, нет, нет …
Комментарии:
1. Это неопределенное поведение или непредсказуемое поведение?
printf
иsprintf
следует продолжать чтение символов, пока они не достигнут значения null.2. Это неопределенное поведение. Предположим, что символ находится на границе «чего-то», и пересечение этой границы запускает самоуничтожение. выполнение
printf("%sn", pMember);
может быть таким же, какselfdestruct(SELFDESTRUCT_IMMED);
🙂
Ответ №3:
Вы где-то перезаписываете буфер. Замените sprintf
на snprintf
, чтобы библиотека C точно знала, сколько места у вас есть в целевом буфере, например:
char buffer[32];
snprintf( buffer, 32, "my text: %sn", some_char_ptr );
Редактировать 0:
Строки в C заканчиваются нулем, что означает, что в конце блока памяти есть один дополнительный байт, который имеет значение ''
и который сигнализирует о конце строки. Это то, что библиотека C предполагает для строковых функций, таких как strlen
и strcpy
, и для %s
спецификатора формата для всех printf
. В противном случае эти библиотечные функции будут работать в памяти до тех пор, пока не будет найден байт с нулевым значением или ОС не убьет вашу программу для доступа к незамеченной памяти.
Комментарии:
1. 1 —
sprintf
в производственном коде ошибка, всегда используйтеsnprintf
2.
snprintf
имеет свое применение. Я не понимаю, как это здесь помогает 😉 — Поскольку это вынуждает вас использовать компилятор C99, это может быть даже контрпродуктивно.3. @pmg — это позволяет избежать одной проблемы, в частности переполнения буфера.
4. Прежде чем беспокоиться о переполнении буфера, оператору следует побеспокоиться о том, чтобы не обрабатывать случайные
char
файлы в памяти как «строковые» 🙂 — и в исходном коде переполнения буфера не было: вpurl
массиве есть место для 1024 символов.5. Я бы сказал, что snprintf в производственном коде также является ошибкой, если только вы не имеете дело с большим количеством форматирования с плавающей запятой в строку. s * printf не только занимает огромные объемы памяти, но и работает очень медленно. Если вы выполняете только преобразование int-to-string / строка-в-int, напишите для этого свои собственные процедуры. 30 минут работы, а затем вы повторно используете их во всех своих проектах программирования в будущем.