C语言凯撒密码代码中循环自增的异常行为疑问
凯撒密码实现中的循环索引与字符串终止问题
先看你给出的代码:
char arr[SIZE]; fgets(arr, SIZE, stdin); char brr[SIZE]; int i; for(i=0; arr[i] != '\0'; i++){ if(arr[i] != ' ') brr[i] = (arr[i] + shift - 'a')%26 + 'a'; else brr[i] = ' '; } brr[i-1] = '\0';
你的疑惑点在于:明明觉得应该用brr[i] = '\0',但实际必须用i-1,而且循环结束后i会自增一次——这本质是fgets读取的字符串包含换行符,再加上for循环的执行逻辑导致的。
问题拆解
- fgets的行为:当你输入
car并按下回车时,fgets会把'c'、'a'、'r'、'\n'(换行符)都读入arr数组,最后自动追加'\0'作为字符串终止符。此时arr的内容是:['c','a','r','\n','\0']。 - for循环的执行流程:for循环是先判断条件
arr[i] != '\0',满足就执行循环体,然后执行i++。所以整个循环的执行过程是:- i=0:arr[0]='c'≠'\0',处理字符,i变成1
- i=1:arr[1]='a'≠'\0',处理字符,i变成2
- i=2:arr[2]='r'≠'\0',处理字符,i变成3
- i=3:arr[3]='\n'≠'\0',处理字符(因为'\n'不是空格,会被移位),i变成4
- i=4:arr[4]='\0',条件不满足,退出循环
此时i的值是4,你用brr[i-1] = '\0'其实是把brr[3](也就是处理后的换行符)覆盖成终止符,但这不是正确的处理方式——你本来就不该处理换行符。
解决方案
核心是先去掉fgets读入的换行符,让循环只处理用户输入的有效文本:
char arr[SIZE]; fgets(arr, SIZE, stdin); // 移除换行符 size_t len = strlen(arr); if (len > 0 && arr[len - 1] == '\n') { arr[len - 1] = '\0'; } char brr[SIZE]; int i; for(i=0; arr[i] != '\0'; i++){ if(arr[i] != ' ') brr[i] = (arr[i] + shift - 'a')%26 + 'a'; else brr[i] = ' '; } // 现在i的值等于有效字符的长度,直接设置终止符 brr[i] = '\0';
这样处理后,输入car回车,arr的内容会变成['c','a','r','\0'],循环到i=3时,arr[3]是'\0',条件不满足,退出循环,此时i=3,brr[i] = '\0'正好把终止符放在处理后的字符后面,得到正确的'ect'。
另外你提到while循环也有同样问题,道理是一样的——只要arr里包含换行符,循环就会遍历到它,最后导致i的位置超出有效字符范围。
内容的提问来源于stack exchange,提问作者ahmet
相关产品推荐
相关产品推荐

