使用指针遍历字符串:第二种写法为何输出多余换行?
我最近尝试用两种指针方式打印字符串的每第4个字符,第一种用char指针的写法完全正常,但换成int指针后,输出完预期的W、T、H后多了四个换行,实在想不通为什么循环没在遇到字符串末尾的NULL时终止。
第一种正确的char指针实现
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]){ char* string = "WhatTheeHell"; char* p = string; while(*p != '\0'){ printf("%c\n", *p); p += 4; } return 0; }
这段代码的输出符合预期:
W T H
出问题的int指针实现
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]){ char* string = "WhatTheeHell"; int* p = (int*)string; while(*p != '\0'){ printf("%c\n", *p); p += 1; } return 0; }
运行后输出W、T、H后还跟着四个换行,循环没有按预期终止。
问题原因解析
这背后的核心问题是你混淆了单字节的字符串终止符\0和4字节的int类型0,再加上违反了C标准的严格别名规则,导致了未定义行为:
指针访问的单位完全不同
char指针每次访问1字节,所以*p != '\0'是检查当前指向的单个字节是否为0;但int指针每次会读取连续4个字节组成的整数值,只有当这4个字节全为0时,*p才会等于0。而你的字符串"WhatTheeHell"末尾只有1个字节的\0,后面的3个字节是内存中的随机垃圾值,所以*p永远不会等于0,循环会继续往后读取超出字符串范围的内存。printf的%c处理逻辑
当你用printf("%c\n", *p)时,*p是一个int值,%c会把这个int截断为unsigned char,只取最低字节来打印。在打印完H之后,后续的int值最低字节可能是字符串末尾的\0(打印空白)或者其他垃圾字节,所以会出现多余的换行。违反严格别名规则
C标准规定,不能用不同类型的指针访问同一块内存(char指针除外),把char指针强制转换为int指针并解引用的行为属于未定义行为,不同编译器、平台可能会出现不同的奇怪表现,这也是代码不可靠的原因之一。
总结
如果想实现“每4个字符打印一个”的逻辑,老老实实用char指针的方式就好,既符合标准又逻辑清晰。用int指针的思路从根本上就错了,因为它的访问单位和字符串的终止规则完全不匹配。
内容的提问来源于stack exchange,提问作者Gokul

