0

Я изучаю некоторые новые вещи в C++, и я пытался протестировать эту функцию strncpy_s из Visual C++. Однако я сталкиваюсь с некоторыми проблемами, поскольку сбой программы и я не знаю, что происходит, но я уверен, что это довольно глупая проблема. Исходный код что-то вроде этого:Как использовать функцию strncpy_s из visual C++?

#include "stdafx.h" 
#include <iostream> 
#include <cstdio> 
#include <cstring> 

int main() 
{ 
    char *p; 
    p=(char *)malloc(sizeof(char)*strlen("Hello!\n")); 
    strncpy_s(p,strlen("Hello!\n"),"Hello!\n",strlen("Hello!\n")); 
    std::cout << p; 
    std::cout << strlen("Hello!\n") << std::endl; 
    return 0; 
} 

Как я сказал, я не использую зЬй :: строки сога Я хочу попробовать эту новую функцию и знать, как это работает.

+0

Используйте отладчик, чтобы узнать, где произошел сбой. Stackoverflow не является отладчиком. –

+0

Я сделал это. Проблема заключалась в вызове функции strncpy_s. – Victor

+0

Я скопирую текст, который я написал в теме вопроса: «Как я уже сказал, я не использую std :: string coz Я хочу попробовать эту новую функцию и знать, как она работает». – Victor

ответ

2

Беру свои комментарии назад, я более внимательно прочитать the documentation. Ваш код передает недопустимые параметры и вызывает недопустимый обработчик параметров. Возможно, это то, что происходит. А именно:

p=(char *)malloc(sizeof(char)*strlen("Hello!\n")); 

Эта линия выделяет место для 7 символов, что является длиной строки, но не достаточно мест для пустого терминатора. (Это, как правило, ошибка)

В документации для strncpy_s указано: Эти функции пытаются скопировать первые D-символы strSource в strDest, где D - меньшее количество count и длина strSource. Если эти символы D будут соответствовать в пределах strDest (размер которого задан как numberOfElements) и по-прежнему оставляют место для нулевого терминатора, то эти символы копируются и завершающий нуль добавляется; , в противном случае strDest [0] устанавливается в нулевой символ, а недопустимый обработчик параметра вызывается, как описано в разделе «Проверка параметров».

Возможно, вы видите «недопустимый обработчик параметров»?

+0

true, там должен быть +1. – Victor

1

strlen(s) сообщит вам только длину строки без терминатора NUL. Чтобы выделить пространство для копирования строки, вы обычно используете strlen(s)+1, чтобы добавить место для терминатора NUL.

+0

Должно быть, я очень глуп, я не мог этого понять, просто. – Victor

+0

@Victor: Любой, кто не допустил эту ошибку хотя бы один раз, вероятно, не программист на C. Время, когда оно становится уродливым, - это когда вы случайно делаете: 'strlen (s + 1)', который все еще компилируется, но дает неправильный ответ (слишком маленький на 2 вместо 1), но ошибка еще проще пропустить. –

0

Почему вы используете malloc или char *, если используете C++?

std::string p = "Hello!\n"; 
std::cout << p; 
std::cout << p.length(); 

или

std::string* p = new std::string("Hello!\n"); 
std::cout << p; 
std::cout << p->length(); 

Но чтобы ответить на ваш первоначальный вопрос, который вы, вероятно, необходимо использовать strlen(p) + 1

И если вам нужен символ * из вашей строки вы можете использовать p.c_str()

+0

Как я уже говорил в этой теме, я пытался изучить эту новую функцию, поэтому я не использовал std :: string. – Victor

+0

@Victor: Приносим извинения, я пропустил этот комментарий после блока кода. –

1

Вы необходимо выделить strlen («Hello! \ n») + 1 (для нулевого терминатора). И sizeof (char) совершенно бессмысленна, поскольку sizeof (char) гарантированно равен 1 на всех платформах.

+0

Мне нравится оператор sizeof, поэтому я сделал sizeof (char), его просто классно. – Victor

+2

Код, который не служит цели, не крут. Это просто добавляет сложности. –

+0

Может кто-нибудь придумает машину, где sizeof (char) == 4? ;) – Victor

2

Вам нужен еще 1 символ для символа прекращения ('\0'), поэтому вам необходимо заменить strlen("Hello!\n") на strlen("Hello!\n") + 1. Вы можете сохранить эту длину в некоторой переменной вместо того, чтобы снова звонить strlen. Кроме того, поскольку вы используете C++ вы можете использовать new/delete вместо malloc/free:

int len = strlen("Hello!\n") + 1; 
char *p; 
p = new char[len]; 
strncpy_s(p, len, "Hello!\n", len); 
std::cout << p << len << std::endl; 
delete[] p; 
+0

Вы также можете избежать вычисления длины времени выполнения с помощью 'sizeof 'Hello! \ N" ', а не' strlen ("Hello! \ п") + 1'. Конечно, это работает только для строковых литералов. –

+0

@MikeSeymour: Хорошо. Но я думаю, что «strlen» более «иллюстративен» в этом случае, поскольку это было основной причиной его проблемы. – LihO

2

Строковые функции с улучшенной безопасностью, по сути, предназначены для сбоя, если они сталкиваются с проблемой.

От Microsoft's docs on strncpy_s():

Эти функции пытаются скопировать первые D символов strSource в strDest, где D является меньшим из подсчета, а длина strSource. Если эти символы D будут вписываться в strDest (размер которого задан как numberOfElements) и по-прежнему оставляют место для нулевого терминатора, то эти символы копируются и добавляется завершающий нуль; , в противном случае strDest [0] устанавливается в нулевой символ и вызывается недействительный обработчик параметра , как описано в разделе «Проверка параметров».

Существует исключение из вышеуказанного абзаца. Если count - _TRUNCATE, , то столько strSource, сколько вставляется в strDest, копируется, а все еще оставляет место для завершающего нуля, который всегда добавляется.

description of the Paramter Validation является:

Поведение C Время воспроизведения, когда недопустимый параметр найден является вызова в настоящее время назначен недопустимый обработчик параметров. Недействительный параметр по умолчанию вызывает отчет об авариях Watson, который вызывает сбой приложения и запрашивает у пользователя, хочет ли он загрузить аварийный сбой дамп Microsoft для анализа. В режиме отладки недопустимый параметр также приводит к неудачному утверждению.

Это поведение можно изменить с помощью функции _set_invalid_parameter_handler, чтобы установить недопустимый обработчик параметров в свою собственную функцию. ...

Ваша примерная программа обеспечивает слишком маленький буфер одним char (там нет места для нулевого терминатора).

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

+0

Если «авария лучше, чем ошибка, которая может открыть дыру в безопасности», чем использование такой ошибки приведет к отказу в обслуживании. Отказ службы также является проблемой безопасности, поэтому эта функция на самом деле не является безопасной. – Victor

+0

@ Victor: Я не говорю, что он исправляет все ошибки безопасности. Я даже не даю здесь мнения о том, имеет ли смысл дизайн. Поведение Microsoft по умолчанию здесь - «реализация определена» в соответствии с TR-24731 (это материал в C11? Мне нужно прочитать об этом ...). Я полагаю, что MS считает, что авария в вашем лице предпочтительнее молчаливой дыры в безопасности. Также обратите внимание, что дизайн позволяет избежать сбоя, если вы хотите приложить усилия для этого. Вы можете прочитать объяснение: http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1173.pdf –

+0

Хорошо, Майкл Берр, спасибо. Я не привык читать документы спецификации языков, может быть, я должен это изменить. – Victor