如何在c?
中使用scanf扫描IP地址我已经是用户:
scanf(" %d ", &ip_adress)
我应该使用
%d.%d.%d
或者有一种更简单的方法。
这是我从文件中读取信息的功能:
void read_tree_from(FILE *in, PC **root){
char name[MAX_NAME];
int ip_adress;
int speed;
while(fscanf(in, "%s %d %d", name, &ip_adress, &speed) != EOF){
PC *new = create_new_item(name, ip_adress, speed);
add_to_tree(new, root);
}
}
但是当我运行该程序时,它工作正常,但在输出文件中它的混乱......
答案 0 :(得分:4)
您可以使用格式说明符%hhu.%hhu.%hhu.%hhu
,它读取无符号的8位值,您可以直接读取ip地址的int表示的4个字节:
int main () {
const char* testLine = "aName 192.168.112.54 100";
char name[100];
int speed;
volatile uint32_t ipAddress=0;
unsigned char* ipAddressBytes = (unsigned char*)&ipAddress;
if (sscanf(testLine, "%s %hhu.%hhu.%hhu.%hhu %d", name, ipAddressBytes+3, ipAddressBytes+2,ipAddressBytes+1,ipAddressBytes+0, &speed) == 6) {
printf("%s %08X %d\n",name, ipAddress, speed);
}
return 0;
}
输出:
aName C0A87036 100
格式%hhu
读取整数值并将其映射到8位;因此,它不会检查有关IP地址的输入在1025.168.112.54
无效的意义上是否有效。但是,它避免了技术溢出,因为任何超过8位的部分都会被忽略。所以在提到之前输入会产生01A87036
。
注意volatile
- 说明符,它告诉编译器它不应该优化对这个变量的访问;否则,编译器可能会认为 - 由于该值没有明显改变 - 变量未更改/未初始化。
进一步注意,您必须注意您的环境是大端还是小端架构。
希望它有所帮助。
答案 1 :(得分:1)
如何使用fscanf扫描IP地址
使用行数据,==81480== 154,839 bytes in 81 blocks are definitely lost in loss record 1,258 of 1,259
==81480== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==81480== by 0x4ED9777: ??? (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4EA81D8: PyUnicode_New (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4EABFDC: _PyUnicode_FromASCII (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4FA073C: ??? (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4EE8038: PyCFunction_Call (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4FF41B4: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4FF4638: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x5084CAB: ??? (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x5084D82: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4FEC9CA: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480== by 0x4FF967C: ??? (in /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0)
==81480==
> ==55233==
> ==55233==
> ==55233== HEAP SUMMARY:
> ==55233== in use at exit: 2,642,149 bytes in 4,750 blocks
> ==55233== total heap usage: 42,001 allocs, 37,251 frees, 34,675,848 bytes allocated
> ==55233==
> ==55233== LEAK SUMMARY:
> ==55233== definitely lost: 157,656 bytes in 85 blocks
> ==55233== indirectly lost: 0 bytes in 0 blocks
> ==55233== possibly lost: 158,663 bytes in 90 blocks
> ==55233== still reachable: 2,325,830 bytes in 4,575 blocks
> ==55233== suppressed: 0 bytes in 0 blocks
> ==55233== Rerun with --leak-check=full to see details of leaked memory
> ==55233==
> ==55233== For counts of detected and suppressed errors, rerun with: -v
> ==55233== Use --track-origins=yes to see where uninitialised values come from
> ==55233== ERROR SUMMARY: 3460 errors from 123 contexts (suppressed: 0 from 0)
有许多优势,包括比fgets()
更好的错误恢复,因此fscanf()
解决方案
fgets/sscanf()
或者有一种更简单的方式(?)
是的,如果代码不关心检测错误数据,可以使用许多快捷方式。生产代码检查错误数据。强大的检查将采用void read_tree_from(FILE *in, PC **root){
char buffer [MAX_NAME + 50];
// Read a line of input
if (fgets(buffer, sizeof buffer, in)) {
int ip_address;
int speed;
unsigned char octet[4];
int n = 0;
int namelen;
// This approach uses %n to record the scan offset - if it got that far
// %*s%n to scan over the name, all tht is needed is how long it is
// %hhu to scan an `unsigned char`
// " ." to scan spaces and then a '.'
sscanf(buffer, "%*s%n %hhu .%hhu .%hhu .%hhu %d %n",
&namelen, &octet[0], &octet[1], &octet[2], &octet[3], &speed, &n);
// When `n > 0`, the complete scan occurred
// buffer[n] != '\0' detects extra junk after the speed
if (n == 0 || buffer[n] != '\0') {
// failed scan
return;
}
// Check data for validity
if (namelen >= MAX_NAME) {
// name too long
return;
}
buffer[namelen] = '\0'; // \0 terminate the name
// form IP address. I'd recommend `uint32_t` rather than `int`
// The `1u*` insures code deals with unsigned promotions and shifts. No sign extend
ip_address = 1u*octet[0] << 24 | 1u*octet[1] << 16 | 1u*octet[2] << 8 | octet[3];
PC *new = create_new_item(buffer, ip_adress, speed);
add_to_tree(new, root);
}
}
}
并查找超出范围的数值,(可能使用strtoul)等。
答案 2 :(得分:0)
我第一次尝试了这个,但它没有工作,可能是bcs我在代码中的其他地方有一些错误,我认为这是制作eror的部分。但是当我修复我的代码中的一些错误时,它工作。
while(fscanf(in, "%d %s %s %d", tmp_number, tmp_name, tmp_ip, &tmp_speed) != EOF){
RACUNAR *new = create_new_item(tmp_number, tmp_name, tmp_ip, tmp_speed);
add_to_tree(new, root);