char 数组 C 末尾的奇怪字符
Weird characters at the end of char array C
我试着写了一篇 implementation of the Weasel Program。我编译了三个版本,都完全相同,名称为“weasel.exe”、“weasel2.exe”和“weasel3.exe”。 “weasel.exe”产生预期的输出,
Gen 0: YPSZNCWPSDUMLYKRIKNSEOJCERIL
Gen 10: YPSZNCWPSDUMLYKRIKNSE JCERIL
Gen 92: YPSZNCKPSDUMLYKRIKNSE JCERIL
Gen 129: YPSZNCKPSDUMLYKRIKNSE JCEREL
Gen 240: YPSZICKPSDUMLYKRIKNSE JCEREL
Gen 388: YPSZICKPSDTMLYKRIKNSE JCEREL
Gen 570: YPSZICKPSDTMLYKRIKNSE JEEREL
Gen 634: YPSZICKPSDTMLYKRIKN E JEEREL
Gen 1102: YPSZICKPSDTMLSKRIKN E JEEREL
Gen 1185: YPSZICKPYDTMLSKRIKN E JEEREL
Gen 1223: YESZICKPYDTMLSKRIKN E JEEREL
Gen 1491: YESZICKPYITMLSKRIKN E JEEREL
Gen 1613: YESZICKPYITMISKRIKN E JEEREL
Gen 1627: YETZICKPYITMISKRIKN E JEEREL
Gen 1750: YETZICKPYITMISKRIKN E WEEREL
Gen 1855: YETZICKPJITMISKRIKN E WEEREL
Gen 2461: METZICKPJITMISKRIKN E WEEREL
Gen 2536: METZICKPJITMIS RIKN E WEEREL
Gen 2876: METZICKPJITMIS JIKN E WEEREL
Gen 3354: METZICKPJITMIS JIKN E WEAREL
Gen 3668: METZICKPJITMIS JIKN E WEASEL
Gen 3837: METZINKPJITMIS JIKN E WEASEL
Gen 3938: METZINKP ITMIS JIKN E WEASEL
Gen 4147: METHINKP ITMIS JIKN E WEASEL
Gen 4314: METHINKP ITMIS JIKE E WEASEL
Gen 4803: METHINKP ITMIS JIKE A WEASEL
Gen 5441: METHINKP ITMIS LIKE A WEASEL
Gen 6090: METHINKS ITMIS LIKE A WEASEL
Gen 7712: METHINKS IT IS LIKE A WEASEL
但是“weasel2.exe”产生这个
Gen 896: CB FNEOJWT WAVACDESTKWELIEF/c PnW~lcÏ
Gen 897: CB FNEOJWT WAVACDESTKWELIEF
Gen 981: CP FNEOJWT WAVACDESTKWELIEF
Gen 1014: CP FNEOJWT WAVLCDESTKWELIEFOWSE'•&E
Gen 1015: CP FNEOJWT WAVLCDESTKWELIEF
Gen 1087: CP FNEOJWT WAVLCDESTKWELSEF/c PnW~lcÏ
数组末尾有额外的不需要的字符。对于某些世代,这包括看起来像我的 PATH 环境变量的部分内容。从我读到的其他 SO 问题来看,这是因为数组末尾没有“\0”字符,但是当我添加
[Line 75] offspring[i][28] = '[=12=]';
对于后代分配循环,程序因内存访问冲突而崩溃。甚至允许写入的最低索引是 8。“weasel2.exe”永远运行,虽然一些字符确实匹配 weasel 字符串,但其他字符会无限期地继续更改,即使它们确实设法 'evolve' 到正确的字符。 “weasel3.exe”每次都因内存访问冲突而崩溃。编译时我收到这些警告:
weasel2.c:85: warning: assignment from incompatible pointer type
weasel2.c:89: warning: assignment from incompatible pointer type
但据我所知这不是问题的原因(但我也可能错了)。
这是什么原因造成的,为什么行为仅在编译之间有所不同,而不是对每个单独的程序进行测试?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int randomNumber(int high) {
return rand() % high;
}
int generateOffspring(char* currentGen, int currentLen, char* letters, char** offspring, unsigned long children, int probability) {
for (unsigned int i = 0; i < children; i++) {
for (unsigned int c = 0; c < currentLen; c++) {
if (randomNumber(probability) < 1) {
offspring[i][c] = letters[randomNumber(27)];
}
else {
offspring[i][c] = currentGen[c];
}
}
}
return 0;
}
int findLeastDistance(char* string, char** strings, int len, int count) {
unsigned int matches = 0;
unsigned int bestMatches = 0;
unsigned int bestMatch = 0;
for (unsigned int i = 0; i < count; i++) {
for (unsigned int c = 0; c < len; c++) {
if (string[c] == strings[i][c]) {
matches++;
}
}
if (matches > bestMatches) {
bestMatches = matches;
bestMatch = i;
}
matches = 0;
}
return bestMatch;
}
int main(int argc, char *argv[]) {
system("PAUSE");
time_t t;
srand((unsigned)time(&t));
unsigned int probability;
if (argc == 2) {
probability = (int)argv[1];
}
else {
probability = 10000;
}
unsigned int children = 100;
char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
char target[] = "METHINKS IT IS LIKE A WEASEL";
char currentGen[29];
for (unsigned int i = 0; i < 29; i++) {
currentGen[i] = letters[randomNumber(27)];
}
char** offspring[children];
for (unsigned int i = 0; i < children; i++) {
offspring[i] = malloc(29);
}
unsigned int bestMutation;
unsigned int counter = 0;
for (;;) {
generateOffspring(currentGen, 28, letters, offspring, children, probability);
bestMutation = findLeastDistance(target, offspring, 28, children);
if (strcmp(currentGen, offspring[bestMutation])) {
printf("Gen %d: %s\n", counter, offspring[bestMutation]);
}
strcpy(currentGen, offspring[bestMutation]);
if (!strcmp(currentGen, target)) {
break;
}
counter++;
}
for (unsigned int i = 0; i < children; i++) {
free(offspring[i]);
}
free(currentGen);
printf("\nEnd\n");
return 0;
}
第一步,按如下方式更改 generateOffspring
循环:
for (unsigned int c = 0; c < currentLen - 1; c++) {
if (randomNumber(probability) < 1) {
offspring[i][c] = letters[randomNumber(27)];
}
else {
offspring[i][c] = currentGen[c];
}
}
offspring[i][currentLen - 1] = 0; // terminate offspring[i]
请记住,要存储 N 个字符长的字符串,您需要一个至少有 N+1 个元素长的数组来存储 0 终止符。
正如 Antti Haapala 指出的那样,currentGen
也有同样的问题,因此您需要将该循环更改为
for (unsigned int i = 0; i < 28; i++) {
currentGen[i] = letters[randomNumber(27)];
}
currentGen[28] = 0;
我试着写了一篇 implementation of the Weasel Program。我编译了三个版本,都完全相同,名称为“weasel.exe”、“weasel2.exe”和“weasel3.exe”。 “weasel.exe”产生预期的输出,
Gen 0: YPSZNCWPSDUMLYKRIKNSEOJCERIL
Gen 10: YPSZNCWPSDUMLYKRIKNSE JCERIL
Gen 92: YPSZNCKPSDUMLYKRIKNSE JCERIL
Gen 129: YPSZNCKPSDUMLYKRIKNSE JCEREL
Gen 240: YPSZICKPSDUMLYKRIKNSE JCEREL
Gen 388: YPSZICKPSDTMLYKRIKNSE JCEREL
Gen 570: YPSZICKPSDTMLYKRIKNSE JEEREL
Gen 634: YPSZICKPSDTMLYKRIKN E JEEREL
Gen 1102: YPSZICKPSDTMLSKRIKN E JEEREL
Gen 1185: YPSZICKPYDTMLSKRIKN E JEEREL
Gen 1223: YESZICKPYDTMLSKRIKN E JEEREL
Gen 1491: YESZICKPYITMLSKRIKN E JEEREL
Gen 1613: YESZICKPYITMISKRIKN E JEEREL
Gen 1627: YETZICKPYITMISKRIKN E JEEREL
Gen 1750: YETZICKPYITMISKRIKN E WEEREL
Gen 1855: YETZICKPJITMISKRIKN E WEEREL
Gen 2461: METZICKPJITMISKRIKN E WEEREL
Gen 2536: METZICKPJITMIS RIKN E WEEREL
Gen 2876: METZICKPJITMIS JIKN E WEEREL
Gen 3354: METZICKPJITMIS JIKN E WEAREL
Gen 3668: METZICKPJITMIS JIKN E WEASEL
Gen 3837: METZINKPJITMIS JIKN E WEASEL
Gen 3938: METZINKP ITMIS JIKN E WEASEL
Gen 4147: METHINKP ITMIS JIKN E WEASEL
Gen 4314: METHINKP ITMIS JIKE E WEASEL
Gen 4803: METHINKP ITMIS JIKE A WEASEL
Gen 5441: METHINKP ITMIS LIKE A WEASEL
Gen 6090: METHINKS ITMIS LIKE A WEASEL
Gen 7712: METHINKS IT IS LIKE A WEASEL
但是“weasel2.exe”产生这个
Gen 896: CB FNEOJWT WAVACDESTKWELIEF/c PnW~lcÏ
Gen 897: CB FNEOJWT WAVACDESTKWELIEF
Gen 981: CP FNEOJWT WAVACDESTKWELIEF
Gen 1014: CP FNEOJWT WAVLCDESTKWELIEFOWSE'•&E
Gen 1015: CP FNEOJWT WAVLCDESTKWELIEF
Gen 1087: CP FNEOJWT WAVLCDESTKWELSEF/c PnW~lcÏ
数组末尾有额外的不需要的字符。对于某些世代,这包括看起来像我的 PATH 环境变量的部分内容。从我读到的其他 SO 问题来看,这是因为数组末尾没有“\0”字符,但是当我添加
[Line 75] offspring[i][28] = '[=12=]';
对于后代分配循环,程序因内存访问冲突而崩溃。甚至允许写入的最低索引是 8。“weasel2.exe”永远运行,虽然一些字符确实匹配 weasel 字符串,但其他字符会无限期地继续更改,即使它们确实设法 'evolve' 到正确的字符。 “weasel3.exe”每次都因内存访问冲突而崩溃。编译时我收到这些警告:
weasel2.c:85: warning: assignment from incompatible pointer type
weasel2.c:89: warning: assignment from incompatible pointer type
但据我所知这不是问题的原因(但我也可能错了)。
这是什么原因造成的,为什么行为仅在编译之间有所不同,而不是对每个单独的程序进行测试?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int randomNumber(int high) {
return rand() % high;
}
int generateOffspring(char* currentGen, int currentLen, char* letters, char** offspring, unsigned long children, int probability) {
for (unsigned int i = 0; i < children; i++) {
for (unsigned int c = 0; c < currentLen; c++) {
if (randomNumber(probability) < 1) {
offspring[i][c] = letters[randomNumber(27)];
}
else {
offspring[i][c] = currentGen[c];
}
}
}
return 0;
}
int findLeastDistance(char* string, char** strings, int len, int count) {
unsigned int matches = 0;
unsigned int bestMatches = 0;
unsigned int bestMatch = 0;
for (unsigned int i = 0; i < count; i++) {
for (unsigned int c = 0; c < len; c++) {
if (string[c] == strings[i][c]) {
matches++;
}
}
if (matches > bestMatches) {
bestMatches = matches;
bestMatch = i;
}
matches = 0;
}
return bestMatch;
}
int main(int argc, char *argv[]) {
system("PAUSE");
time_t t;
srand((unsigned)time(&t));
unsigned int probability;
if (argc == 2) {
probability = (int)argv[1];
}
else {
probability = 10000;
}
unsigned int children = 100;
char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
char target[] = "METHINKS IT IS LIKE A WEASEL";
char currentGen[29];
for (unsigned int i = 0; i < 29; i++) {
currentGen[i] = letters[randomNumber(27)];
}
char** offspring[children];
for (unsigned int i = 0; i < children; i++) {
offspring[i] = malloc(29);
}
unsigned int bestMutation;
unsigned int counter = 0;
for (;;) {
generateOffspring(currentGen, 28, letters, offspring, children, probability);
bestMutation = findLeastDistance(target, offspring, 28, children);
if (strcmp(currentGen, offspring[bestMutation])) {
printf("Gen %d: %s\n", counter, offspring[bestMutation]);
}
strcpy(currentGen, offspring[bestMutation]);
if (!strcmp(currentGen, target)) {
break;
}
counter++;
}
for (unsigned int i = 0; i < children; i++) {
free(offspring[i]);
}
free(currentGen);
printf("\nEnd\n");
return 0;
}
第一步,按如下方式更改 generateOffspring
循环:
for (unsigned int c = 0; c < currentLen - 1; c++) {
if (randomNumber(probability) < 1) {
offspring[i][c] = letters[randomNumber(27)];
}
else {
offspring[i][c] = currentGen[c];
}
}
offspring[i][currentLen - 1] = 0; // terminate offspring[i]
请记住,要存储 N 个字符长的字符串,您需要一个至少有 N+1 个元素长的数组来存储 0 终止符。
正如 Antti Haapala 指出的那样,currentGen
也有同样的问题,因此您需要将该循环更改为
for (unsigned int i = 0; i < 28; i++) {
currentGen[i] = letters[randomNumber(27)];
}
currentGen[28] = 0;