0


c语言安全分析(一)——字符串(1)

文章目录


介绍

嗨,我是艾丽卡,很高兴和你聊聊C语言中的字符串和数组。想象一下,字符串就像一列小火车,每个车厢代表一个字符,而最后一个特别的车厢——空字符

'\0'

——告诉我们火车到站了,也就是字符串的结束。

  1. 界限(Bound):- 这就像数火车车厢的数量,包括那个告诉我们火车结束的特别的车厢。
  2. 低位地址(Lo):- 这是火车队列的第一个车厢的地址,也就是字符串的第一个字符。
  3. 高位地址(Hi):- 这是最后一个车厢的地址,也就是空字符的地址。
  4. TooFar:- 这就像是火车队列结束后,我们再往前多走一步的位置。虽然我们可以指向那里,但是如果真的去那里,就会超出火车的范围,导致未定义行为。
  5. 目标大小(Tsize):- 这就像测量整个火车队列占用的轨道长度,也就是整个字符串包括空字符在内的总字节数。
  6. 空字符结尾(Null-terminated):- 这表示我们的火车队列总是以那个特别的车厢结束,这样我们就知道火车什么时候到站。
  7. 长度(Length):- 这是计算火车车厢数量的方法,但不包括那个特别的结束车厢。

处理字符串时,我们得像列车长一样小心翼翼,确保不会让火车出轨,也就是说,要确保我们的代码不会越界,不会溢出缓冲区,这样才能保证我们的程序既安全又稳定。


一、\0 NULL false

在C语言中,

sizeof

运算符用于获取一个变量或类型在内存中所占的字节数。对于数组,

sizeof(array)

会返回整个数组所占的字节数,包括数组中的所有元素。

当你有一个数组时,比如

char str[] = "hello";

sizeof(str)

会返回字符串 “hello” 所占的字节数,包括最后的空字符(null terminator)

\0

。这是因为在C语言中,字符串是以空字符结尾的字符数组。

C标准确实允许创建指向数组末尾元素之后加1位置的指针。这意味着你可以有一个指针指向数组的最后一个元素之后的位置,但这个位置实际上是数组的“边界之外”。例如:

char str[]="hello";char*ptr = str +sizeof(str)/sizeof(str[0]);

在这个例子中,

ptr

指向的是数组

str

的末尾元素之后的位置,也就是数组的“边界之外”。这个指针是合法的,因为它没有越界,它只是指向了数组末尾元素之后的一个位置。但是,你不能对这个位置进行解引用操作,因为这样做会产生未定义行为,即程序可能会崩溃或者产生不可预测的结果。

在处理字符串时,这个特性可以用来遍历字符串直到遇到空字符。例如,下面的代码可以用来计算字符串的长度:

char str[]="hello";char*ptr = str;while(*ptr){
    ptr++;}int length = ptr - str;

在这个例子中,

ptr

会遍历字符串直到遇到空字符,然后计算出字符串的长度。但是,一旦

ptr

指向了空字符,就不应该再进行解引用操作,因为那会导致未定义行为

#include<stdio.h>intmain(){char str[]="hello";// 包含空字符的字符串char*ptr = str;// 指向字符串的开始// 遍历字符串直到遇到空字符while(*ptr){
        ptr++;// 移动指针但不解引用TooFar位置}// 此时ptr指向TooFar位置,即空字符之后的位置// 我们不应该解引用ptr,因为它指向的是未定义的内存区域// 计算字符串的长度(不包括空字符)int length = ptr - str;printf("The length of the string is: %d\n", length);return0;}
The length of the string is: 5

好奇的是为什么程序while会停止
我们尝试传入\0

#include<stdio.h>intmain(){char str[]="hello";// 包含空字符的字符串char*ptr = str;// 指向字符串的开始// 遍历字符串直到遇到空字符// while (*ptr) {//     ptr++; // 移动指针但不解引用TooFar位置// }while('\0'){
        ptr++;// 移动指针但不解引用TooFar位置}// 此时ptr指向TooFar位置,即空字符之后的位置// 我们不应该解引用ptr,因为它指向的是未定义的内存区域// 计算字符串的长度(不包括空字符)int length = ptr - str;printf("The length of the string is: %d\n", length);return0;}
he length of the string is: 0

可以看出\0可以终止while,而false也可以。

while(false){
        ptr++;// 移动指针但不解引用TooFar位置}
#
  1. \0(空字符):- \0 是一个字符常量,代表ASCII码中的空字符,其整数值是0。在C语言中,字符串以空字符 \0 结尾,这是字符串结束的标志。当 \0 用作条件表达式时,它的值是0,因此在布尔上下文中被视为 false
  2. **false**:- false 是C语言中的一个布尔值,代表逻辑假。在C99及以后的标准中,bool 类型被引入,其中 false 是预定义的布尔值,其值为0。

尽管

\0

false

在整数值上都是0,并且在布尔上下文中都被视为

false

,但它们在语义上是不同的。

\0

用于表示字符串的结束,而

false

用于表示布尔逻辑中的假值。

在C语言中,

NULL

是一个宏,它被定义为一个空指针常量。它的值通常是

(void *)0

,即一个指向

void

类型的指针,其值为0。

NULL

用于表示一个空(或无效)的指针。

NULL

被用在

while

循环的条件中时,它的值实际上是一个指针,而不是一个整数。在C语言中,任何非零值在布尔上下文中都被视为

true

,而零值(包括

NULL

指针)被视为

false

。因此,

while (NULL)

这个条件会被评估为

false

,循环体不会被执行。

这里是一个例子:

#include<stdio.h>intmain(){while(NULL){printf("This will not be printed.\n");}return0;}

在这个程序中,

while

循环的条件是

NULL

,因此条件评估为

false

,循环内部的

printf

语句不会被执行。

总结来说,

NULL

在布尔上下文中被视为

false

,因为它的值是零。这与

\0

(空字符)和

false

(布尔假值)在布尔上下文中的表现是一致的,尽管它们在类型和用途上有所不同。

二,Toofar

在C语言中,越界解引用是指访问数组或字符串超出其有效范围的内存位置。这通常是不安全的,因为它可能导致未定义行为,包括程序崩溃、数据损坏或安全漏洞。下面是一个越界解引用的例子:

#include<stdio.h>intmain(){char str[]="hello";// 字符串字面值,包含空字符'\0'// 故意越界解引用printf("%c\n", str[sizeof(str)/sizeof(str[0])]);// 这将打印空字符'\0'// 越界解引用printf("%c\n", str[sizeof(str)/sizeof(str[0])+1]);// 这将尝试访问空字符之后的内存return0;}
0
□

在这个例子中,

str

是一个字符数组,它包含了字符串 “hello” 和一个空字符

\0

sizeof(str) / sizeof(str[0])

计算得到的是数组中的元素数量,不包括空字符。因此,

str[sizeof(str) / sizeof(str[0])]

是访问数组中最后一个元素(即空字符)的有效操作。

然而,

str[sizeof(str) / sizeof(str[0]) + 1]

尝试访问空字符之后的内存位置,这是一个越界解引用。这个操作是未定义的,因为它访问了数组分配的内存之外的区域。在某些系统和编译器上,这可能导致程序崩溃或不可预测的行为。

越界解引用是编程中应该避免的错误,因为它可能导致严重的安全问题。正确的做法是总是确保在访问数组或字符串时不会超出其界限。在实际编程中,应该使用循环或其他控制结构来确保不会越界,或者使用安全的字符串处理函数,如

strncpy

snprintf

等,它们可以帮助防止缓冲区溢出和越界错误。


标签: c语言 c++ 安全

本文转载自: https://blog.csdn.net/zhuqiyua/article/details/143579922
版权归原作者 艾丽卡和木森的区块链日记 所有, 如有侵权,请联系我们删除。

“c语言安全分析(一)——字符串(1)”的评论:

还没有评论