为什么我的 const 变量在执行时发生变化?
Why my const variable change on execution?
我有一个随机数生成器,它应该是所有执行的相同数字,但数字发生变化并且不是 4 个数字的偶数?
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
srand(1);
int const numero=rand() % 7000 + 1000;
char *caracter;
while (scanf("%s",&caracter)!=EOF){
printf("%i\n",numero);
}
return 0;
}
我使用了一个带有随机名称的 .txt,结果是这样的
masa6144
pupu6144
ogro6144
pelad1oo
pedo0
tucan110
lloron28271
cheso111
正如你所看到的,三个名字的长度都是 4,并且相同,但是在这 3 个都变得奇怪之后,会是什么?
&caracter
是指针本身的地址。它可以是 2(AVR)、4 或 8 个字节长。使用指针作为字符数组毫无意义,但您可以在其中存储 1、3 或 7 个字符的字符串。
char *caracter;
定义了一个未初始化的指针。
您需要为字符串分配内存。
int main(int argc, char const *argv[])
{
srand(1);
int const numero=rand() % 9000 + 1000;
char character[100];
//or char *character = malloc(100);
while (scanf("%99s",caracter)!=EOF){
printf("%s",caracter);
printf("%i\n",numero);
}
return 0;
}
任何半途而废的编译器都会告诉您有问题。不幸的是,许多编译器默认不告诉您是否有任何错误:您需要明确打开警告。使用 GCC 或 Clang,始终使用 -Wall -Wextra -Werror
进行编译。除非调试,否则还要传递 -O
选项,因为没有它会省略一些警告。
$ gcc -O -Wall -Wextra a.c
a.c: In function ‘main’:
a.c:12:21: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
while (scanf("%s",&caracter)!=EOF){
^
a.c:6:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
int main(int argc, char const *argv[])
^
a.c:6:32: warning: unused parameter ‘argv’ [-Wunused-parameter]
int main(int argc, char const *argv[])
scanf("%s",&caracter)
这会将用户键入的单词存储在从地址&caracter
开始的字符数组中。字符数组需要足够大以容纳单词。如果不是,C 不提供任何保护。这是一个 buffer overflow. The consequences of a buffer overflow can be anything (it's undefined behavior)。如果它到达未分配的内存或只读的内存,这可能会导致崩溃,但它也可以覆盖恰好位于那里的任何内容。确切的行为往往在很大程度上取决于处理器、编译器、周围的代码、编译器如何优化它等。
鉴于您看到的行为,显然,在您的测试中,numero
在内存中就在 caracter
之后,并且 caracter
有 4 个字节的空间。请注意,这是变量 caracter
本身,而不是 caracter
指向的东西。当你输入 masa
时,这会填充 caracter
的四个字节,并在 numero
中写入一个空字节。 6144是256的倍数不是巧合,你的平台是little-endian(所有PC和非古董Mac都是little-endian),所以[=16=的内存表示的第一个字节] 是最低有效字节。因此空字节覆盖了最低有效字节,使数字成为 256 的倍数。
我不知道 pelad1oo
发生了什么(你输入了什么?)。使用 tucan110
,很清楚发生了什么:您键入 tucan
,它将 tuca
写入 caracter
和 n
的 4 个字节,并将一个空字节写入低字节numero
的两个字节,使 numero
的值为 0 * 256 + 'n'
其中 'n'
是字符 n
的值,在 ASCII 中为 110 . 对于 lloron
,溢出到 numero
的是 on
和空字节,使得值 0 * 256 * 256 + 'n' * 256 + 0 = 28271
。等等。
当您将指针传递给一个函数时,您必须始终确保它指向某个东西(或者它是一个空指针,如果该函数接受空指针)。如果函数需要数组,则必须确保指针指向足够大的数组。如果该函数写入一个字符串,则它是一个包含最后一个空字符的字符数组。
简单的做法是使 caracter
成为一个足够大的数组。
char caracter[100];
…
scanf("%99s", caracter);
注意 caracter
之前没有 &
:当数组用作值时,它会自动转换为指向数组开头的指针。并注意 %s
中的 99
:这是 scanf
将写入 caracter
的最大字符数(加上一个空字符以结束字符串)。请注意,如果 scanf
向 caracter
写入一个 99 个字符的字符串,则从用户读取的单词可能不完整。
我有一个随机数生成器,它应该是所有执行的相同数字,但数字发生变化并且不是 4 个数字的偶数?
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
srand(1);
int const numero=rand() % 7000 + 1000;
char *caracter;
while (scanf("%s",&caracter)!=EOF){
printf("%i\n",numero);
}
return 0;
}
我使用了一个带有随机名称的 .txt,结果是这样的
masa6144
pupu6144
ogro6144
pelad1oo
pedo0
tucan110
lloron28271
cheso111
正如你所看到的,三个名字的长度都是 4,并且相同,但是在这 3 个都变得奇怪之后,会是什么?
&caracter
是指针本身的地址。它可以是 2(AVR)、4 或 8 个字节长。使用指针作为字符数组毫无意义,但您可以在其中存储 1、3 或 7 个字符的字符串。
char *caracter;
定义了一个未初始化的指针。
您需要为字符串分配内存。
int main(int argc, char const *argv[])
{
srand(1);
int const numero=rand() % 9000 + 1000;
char character[100];
//or char *character = malloc(100);
while (scanf("%99s",caracter)!=EOF){
printf("%s",caracter);
printf("%i\n",numero);
}
return 0;
}
任何半途而废的编译器都会告诉您有问题。不幸的是,许多编译器默认不告诉您是否有任何错误:您需要明确打开警告。使用 GCC 或 Clang,始终使用 -Wall -Wextra -Werror
进行编译。除非调试,否则还要传递 -O
选项,因为没有它会省略一些警告。
$ gcc -O -Wall -Wextra a.c
a.c: In function ‘main’:
a.c:12:21: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
while (scanf("%s",&caracter)!=EOF){
^
a.c:6:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
int main(int argc, char const *argv[])
^
a.c:6:32: warning: unused parameter ‘argv’ [-Wunused-parameter]
int main(int argc, char const *argv[])
scanf("%s",&caracter)
这会将用户键入的单词存储在从地址&caracter
开始的字符数组中。字符数组需要足够大以容纳单词。如果不是,C 不提供任何保护。这是一个 buffer overflow. The consequences of a buffer overflow can be anything (it's undefined behavior)。如果它到达未分配的内存或只读的内存,这可能会导致崩溃,但它也可以覆盖恰好位于那里的任何内容。确切的行为往往在很大程度上取决于处理器、编译器、周围的代码、编译器如何优化它等。
鉴于您看到的行为,显然,在您的测试中,numero
在内存中就在 caracter
之后,并且 caracter
有 4 个字节的空间。请注意,这是变量 caracter
本身,而不是 caracter
指向的东西。当你输入 masa
时,这会填充 caracter
的四个字节,并在 numero
中写入一个空字节。 6144是256的倍数不是巧合,你的平台是little-endian(所有PC和非古董Mac都是little-endian),所以[=16=的内存表示的第一个字节] 是最低有效字节。因此空字节覆盖了最低有效字节,使数字成为 256 的倍数。
我不知道 pelad1oo
发生了什么(你输入了什么?)。使用 tucan110
,很清楚发生了什么:您键入 tucan
,它将 tuca
写入 caracter
和 n
的 4 个字节,并将一个空字节写入低字节numero
的两个字节,使 numero
的值为 0 * 256 + 'n'
其中 'n'
是字符 n
的值,在 ASCII 中为 110 . 对于 lloron
,溢出到 numero
的是 on
和空字节,使得值 0 * 256 * 256 + 'n' * 256 + 0 = 28271
。等等。
当您将指针传递给一个函数时,您必须始终确保它指向某个东西(或者它是一个空指针,如果该函数接受空指针)。如果函数需要数组,则必须确保指针指向足够大的数组。如果该函数写入一个字符串,则它是一个包含最后一个空字符的字符数组。
简单的做法是使 caracter
成为一个足够大的数组。
char caracter[100];
…
scanf("%99s", caracter);
注意 caracter
之前没有 &
:当数组用作值时,它会自动转换为指向数组开头的指针。并注意 %s
中的 99
:这是 scanf
将写入 caracter
的最大字符数(加上一个空字符以结束字符串)。请注意,如果 scanf
向 caracter
写入一个 99 个字符的字符串,则从用户读取的单词可能不完整。