今天写程序时遇到了有关char
和unsighed char
的诡异问题,实质是没有检查char类型的越界。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 1024
#define THRNUM 25
int main(void)
{
char **arr;
char buf[BUFSIZE] = {"abcdefghijklmnopqrstuvwxyz\n"};
int read_len = sizeof(buf);
printf("read_len = %d\n", read_len);
arr = malloc(sizeof(char *) * THRNUM);
if (arr == NULL)
{
perror("malloc()");
exit(EXIT_FAILURE);
}
for (int i = 0; i < THRNUM; i++)
{
arr[i] = malloc(sizeof(char) * read_len);
if (arr[i] == NULL)
{
perror("malloc()");
exit(EXIT_FAILURE);
}
strncpy(arr[i], buf, read_len);
}
for (int i = 0; i < THRNUM; i++)
printf("%s", arr[i]);
printf("\n");
for (int i = 0; i < THRNUM; i++)
{
for (int j = 0; j < read_len; j++)
{
//是大写字母
if (arr[i][j] >= 'A' && arr[i][j] <= 'Z')
{
arr[i][j] += (i + 1);
if (arr[i][j] > 'Z')
arr[i][j] -= 26;
}
//是小写字母
if (arr[i][j] >= 'a' && arr[i][j] <= 'z')
{
arr[i][j] += (i + 1); //bug位置
if (arr[i][j] > 'z')
arr[i][j] -= 26;
}
}
}
for (int i = 0; i < THRNUM; i++)
printf("%s", arr[i]);
for (int i = 0; i < THRNUM; i++)
free(arr[i]);
free(arr);
exit(EXIT_SUCCESS);
}
这是一段很简单的程序:
是在写凯撒密码的解密程序时需要将buf这个数组中的每一个大小写字母+1,+2,+3,…+25保存到arr这个二维数组中。根据printf打印arr数组的结果可以看出开始几行没有出错,后面几行都会有出错:
出错原因在第52行,arr[i][j]为char类型,第一次出错时arr[i][j]为字符’z’(ascii码十进制表示为122),i+1为6,那么arr[i][j] += i+1
的结果为122+6 = 128
,超过了char类型的最大值,然后溢出使arr[i][j] = -128
,导致第53行判断出错。
解决方案:
初期想到的方案是将arr数组改为unsigned char **arr
,这样就不会产生越界了。
正确的输出结果: