我今天一直在弄乱c语言,当我注释掉这段代码中的第三个缓冲区时,我不理解输出的差异:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
void main() {
unsigned char letters[10];
memset(letters, 0x00, 10);
memset(letters, 0x41, 10);
printf(letters);
printf(" Total buffer len: %d bytes\n",strlen(letters));
char nletters[10];
memset(nletters, 0x00, 10);
memset(nletters, 0x42, 10);
printf(nletters);
printf(" Total buffer len: %d bytes\n",strlen(nletters));
int nums[10];
memset(nums, 0x00, 10);
memset(nums, 0x43, 10);
printf(nums);
printf(" Total buffer len: %d bytes\n",strlen(nums));
return 0;
}
区别在于删除了nums缓冲区周围的注释:
AAAAAAAAAA�7ǝ�U Total buffer len: 16 bytes
BBBBBBBBBBAAAAAAAAAA�7ǝ�U Total buffer len: 26 bytes
并保留缓冲区:
AAAAAAAAAA Total buffer len: 10 bytes
BBBBBBBBBBAAAAAAAAAA Total buffer len: 20 bytes
CCCCCCCCCC��U Total buffer len: 14 bytes
我没有得到的是:
出于对圣洁众人的热爱,注释掉第三个缓冲区如何影响其他缓冲区的大小?
缓冲区末尾的额外字节是什么?如何丢失/管理它们(如果我选择串联缓冲区)?
当我选择是否对第三个缓冲区进行注释时,为什么打印缓冲区大小和初始化大小的差异不一致?
缓冲区2应该是10个字节,为什么是20个字节?我不希望它是20,我只要求10。我不认为这是不合理的。
答案 0 :(得分:2)
读数:null-terminated string,buffer overflow,stack things。
C字符串的字符串末尾需要一个额外的\ 0字符,因此您的“字母”和“ nletters”可以存储9字母的实际字符串以及零终止符(默认情况下,您必须将其放置在自己的位置)。 'nums'是一个整数数组,它并不真正适合存储字符串,但是C / C ++不会阻止您这样做。这就是为什么我在上面写“ 40”作为第二个缓冲区的虚拟地址:“ nums”很可能是一个具有32位整数的4x10字节缓冲区。
答案 1 :(得分:0)
以下建议的代码纠正了OP发布代码中的许多(大多数)问题。
注意main()
函数签名的正确声明
请注意代码缩进的一致使用
请注意使用适当的水平间距以提高可读性
请注意,每次调用printf()
请注意使用sizeof
返回缓冲区的大小(根据printf语句声称它们正在显示的内容
请注意,sizeof
和strlen()
都返回size_t
,而不是int
请注意消除magic
数字(例如10)
请注意,应清除不使用那些内容的头文件
现在,建议的代码:
#include <string.h>
#include <stdio.h>
#define MAX_LEN 10
int main( void )
{
unsigned char letters[ MAX_LEN ];
memset( letters, 0x00, sizeof( letters ) );
memset( letters, 0x41, sizeof( letters )-1 ); // keep NUL byte at end
printf( "%s\n", letters ); //format the output,
// use \n so immediately output to terminal
printf( " Total buffer len: %lu bytes\n", sizeof(letters) );
char nletters[ MAX_LEN ];
memset( nletters, 0x00, sizeof( nletters ) );
memset( nletters, 0x42, sizeof( nletters )-1 ); // keep NUL byte at end
printf( "%s\n", nletters ); // format the output,
// use \n so immediately output to terminal
printf( " Total buffer len: %lu bytes\n", sizeof(nletters) );
int nums[ MAX_LEN ]; // 10 integers
memset( nums, 0x00, 10* sizeof( int ) );
memset( nums, 0x43, 9 ); // this only sets first 10 bytes
// NOTE: sizeof( int ) not same as size of char
// so most of array not modified
for( size_t i=0; i< MAX_LEN; i++ )
{
printf( "%d\n", nums[ i ] );
}
printf( " Total buffer len: %lu bytes\n", sizeof(nums) );
return 0;
}
运行以上代码将得到以下输出:
AAAAAAAAA
Total buffer len: 10 bytes
BBBBBBBBB
Total buffer len: 10 bytes
1128481603
1128481603
67
0
0
0
0
0
0
0
Total buffer len: 40 bytes
答案 2 :(得分:0)
您说您一直在搞C,但是不是C。这破坏了C的某些规则。如果您破坏了C的规则,就会发生奇怪的事情 ...我的主要问题您是:您正在阅读哪本书?,因为您当前的那本书对您来说效果不佳...
在C中,字符串以'\0'
结尾。由于letters
不是包含'\0'
字符的字符序列,因此它不是 string ,因此,您不应将其视为一个字符。如果您要在一个字符串中包含10个字符,则实际上至少需要一个 11 数组来为'\0'
腾出空间(您还需要在{{1之后}}。
memset
在C中,char letters[11];
memset(letters, 'a', 10);
letters[10] = '\0';
格式说明符用于打印%zu
的值,例如从size_t
返回的值。 strlen
用于打印%d
值,仅 。
int
出于对所有圣洁者的热爱,注释掉第三个缓冲区如何影响其他缓冲区的大小?
printf("%s\n", letters);
printf("strlen(letters): %zu\n", strlen(letters));
和printf
期望它们的参数为 strings ,但是 string 必须始终包含strlen
。您的数组不包含'\0'
,因此与字符串相关的函数会循环出界并处理超出范围的数据。
作为练习,预测'\0'
...检验您的理论。
缓冲区末尾的多余字节是什么?如何丢失/管理它们(如果我选择串联缓冲区)?
那些多余的字节是未定义的行为,这是一组令人恐惧的单词,意思是“任何事情都可以代替,因为您违反了规则”” ...当您违反C语言的规则时,会发生奇怪的事情 ...
当我选择是否注释第三个缓冲区时,为什么打印缓冲区大小和初始化大小的差异不一致?
再次,不确定的行为,违反规则... 发生奇怪的事情 ...和您正在阅读哪本书?我问的原因似乎是有人使用书本可以很快解决这个问题,所以我认为您只是在猜测 (在C语言中很危险)。通过阅读一本书,您将更快地学习C(就像在中一样)。
缓冲区2应该是10个字节,为什么是20个字节?我不希望它是20,我只要求10。我不认为这是不合理的。
在没有C的情况下,停止告诉C有一个字符串(由一个字符序列组成的strlen((char[]) { 1, 2, 3, 4, '\0', 5 })
)。