我在C工作,我必须连接一些东西。
现在我有这个:
int main(int argc, char *argv[])
{
char tftp_cmd[TFTP_MAX_BUFFER_SIZE];
char ip_server[IP_MAX_LEN];
char file_name[FILE_MAX_LEN];
const char * tftp_get = "tftp -g -r ";
strcpy(&ip_server[0], argv[1]);
strcpy(&file_name[0], argv[2]);
tftp_cmd[0] = '\0';
strcpy(tftp_cmd, tftp_get);
printf("tftp get command = %s\n", tftp_cmd);
strncat(tftp_cmd, file_name, sizeof(tftp_get) + sizeof(file_name));
printf("tftp get command = %s\n", tftp_cmd);
strncat(tftp_cmd, ip_server, sizeof(tftp_get) + sizeof(file_name) + 1);
printf("tftp get command = %s\n", tftp_cmd);
return 0
}
此应用程序返回:
# ./test_app 10.0.0.1 MY_TEST_FILE_17.12.2015
tftp get command = tftp -g -r
tftp get command = tftp -g -r MY_TEST_FILE_17.12.2015
tftp get command = tftp -g -r MY_TEST_FILE_17.12.201510.0.0.1
我想要tftp -g -r MY_TEST_FILE_17.12.2015 10.0.0.1
我使用的好方法?
答案 0 :(得分:2)
首先,请注意/* Start by setting display:none to make this hidden.
Then we position it in relation to the viewport window
with position:fixed. Width, height, top and left speak
for themselves. Background we set to 80% white with
our animation centered, and no-repeating */
.modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8 ) url('../Images/Loader.gif') 50% 50% no-repeat;
}
/* When the body has the loading class, we turn the scrollbar off with overflow:hidden */
body.loading {
overflow: hidden;
}
/* Anytime the body has the loading class, our modal element will be visible */
body.loading .modal {
display: block;
}
基本上与&ip_server[0]
相同,第二ip_server
不会做你认为它做的事情。
下面
sizeof
相反,做一些像
这样的事情strncat(tftp_cmd, file_name, sizeof(tftp_get) + sizeof(file_name));
strcat(tftp_cmd, file_name);
必须指向足够大的内存缓冲区。
使用tftp_cmd
可能非常危险,因为它可能会遗漏终止strncat()
。
当'\0'
成为tftp_cmd
的第一个参数时,您也不需要初始化strcpy()
,但您需要它指向足够大的内存缓冲区。而且您根本不需要复制argv[1]
和argv[2]
,您可以直接使用它们。如果必须,您可以使用指针而不是复制昂贵的内存。
最后,正如EugeneSh.中@ comment所建议的那样,最好的方法是snprintf()
,这是一个例子
int main(int argc, char *argv[])
{
char *tftp_cmd;
ssize_t length;
const char *format;
format = "tftp -g -r %s %s";
if (argc < 3) // Check that parameters were passed to the funcion
return -1;
length = snprintf(NULL, 0, format, argv[2], argv[1]);
tftp_cmd = malloc(length + 1);
if (tftp_cmd == NULL)
return -1; // Allocation Error
sprintf(tftp_cmd, format, argv[2], argv[1]);
// Use the `tftp_cmd' here, for example
fprintf(stdout, "%s\n", tftp_cmd);
// And then, free it
free(tftp_cmd);
return 0;
}
答案 1 :(得分:2)
显然,所提供的代码存在各种问题:
strcpy(&ip_server[0], argv[1]);
)strncat
的第三个参数是第二个参数的最大大小,而不是连接字符串的最大大小。示例代码中提供的值允许缓冲区溢出。更重要的是,一般方法既难以阅读又效率低下。 C语言中的字符串处理有点烦人,但自1989年以来C字符串库已经有了重大改进,使用新的库函数可以使代码更安全,更易读,更高效。好的C代码应该可以最佳地利用库功能。
(在原始代码中重复使用strncat
是低效的,因为strncat
将在每次调用时从头开始重新扫描输出字符串,从而导致字符串变长时的二次执行时间。)
更好的方法是使用snprintf
来提供简单,易读,安全和有效的格式化操作:
int main(int argc, char** argv) {
if (argc < 3) {
fprintf(stderr, "Too few arguments.\n");
exit(1);
}
/* These are for documentation; no copying is involved */
const char* file_name = argv[2];
const char* ip_server = argv[1];
char tftp_cmd[TFTP_MAX_BUFFER_SIZE];
int outlen = snprintf(tftp_cmd, sizeof tftp_cmd,
"tftp -g -r %s %s", file_name, ip_server);
if (outlen >= sizeof tftp_cmd) {
fprintf(stderr, "Arguments are too long\n");
exit(1);
}
printf("%s\n", tftp_cmd);
return 0;
}
这可以通过分配内存而不是使用固定大小的缓冲区来改进:
int main(int argc, char** argv) {
if (argc < 3) {
fprintf(stderr, "Too few arguments.\n");
exit(1);
}
char* tftp_cmd = NULL;
const char* file_name = argv[2];
const char* ip_server = argv[1];
int outlen = snprintf(tftp_cmd, 0,
"tftp -g -r %s %s", file_name, ip_server);
tftp_cmd = malloc(outlen + 1);
snprintf(tftp_cmd, outlen + 1,
"tftp -g -r %s %s", file_name, ip_server);
printf("%s\n", tftp_cmd);
free(tftp_cmd);
return 0;
}
一些现代C库实现asprintf
,它自动进行内存分配,更方便,因为它避免了两次调用snprintf
。
int main(int argc, char** argv) {
if (argc < 3) {
fprintf(stderr, "Too few arguments.\n");
exit(1);
}
char* tftp_cmd = NULL;
const char* file_name = argv[2];
const char* ip_server = argv[1];
if (0 > asprintf(&tftp_cmd,
"tftp -g -r %s %s", file_name, ip_server)) {
fprintf(stderr, "Memory allocation error\n");
exit(1);
}
printf("%s\n", tftp_cmd);
free(tftp_cmd);
return 0;
}
答案 2 :(得分:1)
以下代码更正了发布代码中发现的问题。
int main(int argc, char *argv[])
{
char tftp_cmd[TFTP_MAX_BUFFER_SIZE];
char ip_server[IP_MAX_LEN];
char file_name[FILE_MAX_LEN];
const char * tftp_get = "tftp -g -r ";
if( 3 != argc )
{
fprintf( stderr, "USAGE: %s <serverIP> <filename>\n", argv[0]);
exit( EXIT_FAILURE );
}
// implied else, correct number of command line parameters
strcpy(ip_server, argv[1]);
strcpy(file_name, argv[2]);
// tftp_cmd[0] = '\0'; -- not needed because first data is set by strcpy()
strcpy(tftp_cmd, tftp_get);
printf("tftp get command = %s\n", tftp_cmd);
strcat(tftp_cmd, file_name);
printf("tftp get command = %s\n", tftp_cmd);
strcat(tftp_cmd, ip_server );
printf("tftp get command = %s\n", tftp_cmd);
return 0
}
但是,对strcat()
的一系列调用可能(可能)溢出tftp_cmd[]
缓冲区。并且发布的代码正在尝试使用strncat()
,因此以下内容更安全,因为它不会溢出tftp_cmd []缓冲区。
int main(int argc, char *argv[])
{
char tftp_cmd[TFTP_MAX_BUFFER_SIZE];
char ip_server[IP_MAX_LEN];
char file_name[FILE_MAX_LEN];
const char * tftp_get = "tftp -g -r ";
if( 3 != argc )
{
fprintf( stderr, "USAGE: %s <serverIP> <filename>\n", argv[0]);
exit( EXIT_FAILURE );
}
// implied else, correct number of command line parameters
strcpy(ip_server, argv[1]);
strcpy(file_name, argv[2]);
// tftp_cmd[0] = '\0'; -- not needed because first data is set by strcpy()
strncpy(tftp_cmd, tftp_get, TFTP_MAX_BUFFER_SIZE);
printf("tftp get command = %s\n", tftp_cmd);
strncat(tftp_cmd, file_name. TFTP_MAX_BUFFER_SIZE - strlen( tftp_cmd ) );
printf("tftp get command = %s\n", tftp_cmd);
strncat(tftp_cmd, ip_server, TFTP_MAX_BUFFER_SIZE - strlen( tftp_cmd );
printf("tftp get command = %s\n", tftp_cmd);
return 0
}
但是,这并未提供缓冲区实际包含整个数据字符串的任何指示。
因此可以在return
语句
if( (strlen( tftp_get) + strlen( file_name ) + strlen( ip_server ) +1 ) > TFTP_MAX_BUFFER_SIZE )
{
printf( "unable to create the full contents of the tftp command\n" );
}