sizeof和strlen的对比与一些杂记
1.sizeof和strlen的对比
1.1sizeof
(1)sizeof是一种操作符
(2)sizeof计算的是类型或变量所占空间的大小,单位是字节
注意事项:
(1)
sizeof
返回的值类型是size_t
,这是一个无符号整数类型格式控制符为: %zu
(2)sizeof中的表达式并不会计算
如上图:如果计算,c应该等于1才对
虽然a、b都是int型,占4个字节
但最终是赋值给c,c是short型,只占2个字节
所以sizeof计算的是short类型的大小
(2.1)不计算的原因:
(2.1.1)sizeof在编译时进行计算,而不是在运行时
编译器会根据表达式的类型来确定其大小,而不是实际去计算表达式的值。
(2.1.2)这种设计避免了运算,可以提高程序的效率
1.2strlen
strlen 是c语言库函数,功能是求字符串的长度
(1)传入的参数是一个指向字符串首字符的指针
这个指针实际上是
指向整个字符串起始位置的地址
(2)返回值是
从字符串的起始位置到第一个空字符(
'\0'
)之前的字符数量,但不包括空字符本身
注意事项:
(1)使用时包含头文件<string.h>
(2)所求字符串必须以空字符结尾,否则返回的是随机值
改进
总结:
2.\0与0的区别
(1)\0,是一个字符常量,表示空字符
在ASCII码表中,
\0
的值是0\0是一个字符类型的值,通常用于表示字符串的结束
(2)类型是char或unsigned char
(1)0,是一个整数常量,表示数值0
(2)0 的类型可以是任何整数类型,如
int
、short
、long
具体取决于上下文和编译器如何处理字面量
3.数组元素的默认值
在C语言中,以下几种情况下的数组元素会被初始化为0:
一、全局数组或静态数组
(1)在所有函数外部定义的全局数组,如果未被显式初始化,则根据C99标准及其后的版本,数组元素会被隐式初始化为0
(2)静态数组如果未被显式初始化,则通常会被初始化为0
二、部分初始化的数组
当数组被部分初始化时,未初始化的元素会被自动填充为0
三、使用特定函数初始化的数组:
calloc函数在分配内存的同时会将内存中的所有字节都初始化为0
4.函数参数的传递顺序
(1)函数参数的传递顺序是从右到左
即,最右边的参数最先被压入栈中,而最左边的参数最后被压入栈中
(2)C语言标准并没有严格规定参数的求值顺序
所以在编写C语言代码时,
应该避免依赖于特定的传参顺序或参数求值顺序
5.格式控制说明符
格式控制说明符 描述 示例 %d
或%i
输出有符号十进制整数 printf("%d", 123);
输出123
%u
输出无符号十进制整数 printf("%u", 456U);
输出456
%o
输出无符号八进制整数 printf("%o", 0123);
输出123
(八进制)%x
或%X
输出无符号十六进制整数 printf("%x", 0xABC);
输出abc
(小写)<br>printf("%X", 0xABC);
输出ABC
(大写)%f
输出十进制浮点数 printf("%f", 3.14159);
输出3.141590
(默认6位小数)%e
或%E
输出科学计数法形式的浮点数 printf("%e", 3.14159);
输出3.141590e+00
<br>printf("%E", 3.14159);
输出3.141590E+00
%g
或%G
自动选择 %f
或%e
/%E
格式输出浮点数printf("%g", 123456.789);
可能输出123456.789
<br>printf("%G", 1.23456789e-10);
可能输出1.234568E-10
%c
输出单个字符 printf("%c", 'A');
输出A
%s
输出字符串 printf("%s", "Hello, World!");
输出Hello, World!
%p
输出指针的地址 printf("%p", (void*)&var);
输出变量var
的地址%%
输出百分号字符 printf("%%");
输出%
字段宽度和精度的示例:
格式控制说明符 描述 示例 %5d
输出至少5个字符宽度的整数,右对齐,不足部分填充空格 printf("%5d", 42);
输出42
(前面有3个空格)%-5d
输出至少5个字符宽度的整数,左对齐,不足部分填充空格 printf("%-5d", 42);
输出42
(后面有3个空格)%05d
输出至少5个字符宽度的整数,右对齐,不足部分用零填充 printf("%05d", 42);
输出00042
%.2f
输出浮点数,保留两位小数 printf("%.2f", 3.14159);
输出3.14
%6.2f
输出浮点数,总宽度至少6个字符,保留两位小数,右对齐 printf("%6.2f", 3.14);
输出3.14
(前面有2个空格)对齐标志的示例(注意:对齐标志通常与字段宽度一起使用):
格式控制说明符 描述 示例 %-d
左对齐整数输出 printf("%-5d", 42);
输出42
(左对齐,后面有3个空格)%+d
在整数前面显示正号或负号 printf("%+d", 42);
输出+42
<br>printf("%+d", -42);
输出-42
% d
(空格与%
之间有一个空格)在正整数前面显示空格,在负整数前面显示负号 printf("% d", 42);
输出42
(前面有一个空格)<br>printf("% d, -42);
输出-42
---来源:文心一言
6.字符串的输入与输出
一、字符串输入
(1)scanf:
使用
%s
读取字符串,直到遇到空白字符(空格、制表符、换行符)注意避免缓冲区溢出,可指定宽度如
%99s
示例:
char str[100]; scanf("%99s", str);
(2)fgets:
从指定流(如
stdin
)读取最多n-1
个字符或直到遇到换行符,并在字符串末尾自动添加
\0
。换行符也会被读取并存储在字符串中(除非流已到达文件末尾)
示例:
char str[100]; fgets(str, sizeof(str), stdin);
二、字符串输出
(1)printf:
使用
%s
输出字符串,直到遇到字符串末尾的\0
示例:
char str[] = "Hello, World!"; printf("%s\n", str);
(2)puts:
输出字符串,
直到遇到字符串末尾的
\0,
并在末尾自动添加换行符不接受格式说明符
示例:
char str[] = "Hello, World!"; puts(str);
总结:
(1)使用
scanf
输入字符串时,务必指定宽度以限制读取的字符数,防止缓冲区溢出。
(2)fgets
会读取并存储换行符(如果输入中包含)如果不希望换行符出现在字符串中,可以手动去除。
(3)在处理字符串时,始终要注意字符串的长度和存储它的数组的容量,以避免缓冲区溢出等安全问题。
7.变长数组
变长数组是C99标准之后引入的一个特性
它允许数组的长度运行时确定,而不是再编译时
即:
在声明变长数组时
数组的大小可以是一个变量或者是一个表达式的结果
这个变量或表达式的值在运行时才会确定
注意事项:
(1)变长数组不能在声明时初始化
因为变长数组的长度在编译时是不确定的
无法在编译时进行初始化
(2)变长数组的大小在程序运行期间是保持不变的
“变”仅指在创建数组时可以使用变量指定数组长度
而非在数组创建后改变其大小
8.关于gets
gets函数在C11标准中被标记为过时,不推荐使用
这是因为:
如果用户输入的字符串长度超过了数组能够容纳的长度
gets函数会继续将字符写入数组
直到遇到换行符(
\n
)或文件结束符(EOF)导致
缓冲区溢出
可能覆盖内存中的其他数据
引发未定义行为,如程序崩溃、数据损坏或安全漏洞(如栈溢出攻击)
所以
多使用fgets和scanf函数进行字符串的输入操作