【C语言】学习过程教训与经验杂谈:思想准备、知识回顾(五)

 


 🔥个人主页艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》C语言刷题12天IO强训LeetCode代码强化刷题

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平



前言: 我们在学习过程中会碰到很多很多问题,本系列文章不会博主不会额外再创建一个新的专栏来收录,因为这一系列文章创作的初心主要是针对回顾知识点(遵循遗忘曲线并且根据自身的实际情况可以做出一些计划,回顾知识点很重要)、缓解学习过程中的可能出现的焦虑等等。主包就不另外开一个专栏了,uu们可以把本系列的文章作为【C语言】专栏的后日谈来看。

主包学习能力比较一般,学起语言、算法无论是花费的时间精力还是取得的成效和大佬们完全无法比。主包起步也比较晚,主包正儿八经开始学C++是从今年的4月24号开始的,主包学习能力真的很一般,C语言这个基础也不扎实,看主包文章的诸位一定是比主包要强的,但主包学习过程中碰到的麻烦、思考、和做的知识点回顾对大家还是有用的。


目录

正文 

三、知识点回顾

(八)操作符(运算符)

3、单目操作符

(1)逻辑反操作 !

(2)负值 - 和正值 +

(3)取地址 &

(4)类型长度 sizeof

(5)按位取反 ~

(6)自增 ++ 和自减 --

(7)解引用操作符 *

(8)强制类型转换(类型)

应用场景示例

总结——关键注意事项

4、强制类型转换 

(1)整数除法导致精度丢失

(2)指针类型转换带来的地址计算错误

(3)结构体或数组的强制类型转换导致未定义行为

(4)浮点数到整数的转换导致截断

(5)类型不匹配导致编译器警告或错误

结尾


正文 

三、知识点回顾

(八)操作符(运算符)

3、单目操作符

单目操作符:++、- -、+(正)、-(负)。

前置和后置—— 

int a = 10;
int b = a--;//后置--,先使用再-1,b=10,a=9
int b = --a;//前置--,先-1再使用,b=9,a=9
int b = a++;//后置++,先使用,后+1,b=10,a=11
int b = ++a;//前置++,先+1,再使用,b=11,a=11

 单目操作符的使用和示例

单目操作符是指仅需要一个操作数的操作符。在C语言中,单目操作符包括逻辑反操作 !、负值 -、正值 +、取地址 &、类型长度 sizeof、按位取反 ~、自增 ++ 和自减 -- 操作符等。这些操作符通常用于对单一操作数进行特定的操作。

大家来看一个综合实例:

#include <stdio.h>

int main() 
{
    int a = 5;
    int b = -a; // 使用负号操作符
    printf("b = %d\n", b); // 输出: b = -5
    int count = 0;
    printf("count++ = %d\n", count++); // 输出0,然后count变为1
    printf("++count = %d\n", ++count); // count先变为2,然后输出2
    int flag = 0;
    if (!flag) 
    {
        printf("flag is false\n");
    }
    return 0;
}
(1)逻辑反操作 !

逻辑反操作符 ! 用于将一个布尔值取反。如果操作数为真(非零),则结果为假(0);如果操作数为假(0),则结果为真(1)。常用于条件语句中,例如if(!a)表示当 a 为假时执行某段代码。

int a = 5;
int result = !a; // result 的值为 0
(2)负值 - 和正值 +

负值操作符 - 用于将操作数的符号取反,而正值操作符 + 则保持操作数的符号不变。例如:

int a = 5;
int b = -a; // b 的值为 -5
int c = +a; // c 的值为 5
(3)取地址 &

取地址操作符 & 用于获取变量的内存地址。例如:

int a = 10;
int *ptr = &a; // ptr 指向 a 的内存地址

我们和解引用操作符结合一下举个例子(见下文)。 

(4)类型长度 sizeof

sizeof操作符用于获取数据类型或变量所占用的内存大小(以字节为单位)。例如:

int a;
size_t size = sizeof(a); // 获取 int 类型的大小
(5)按位取反 ~

按位取反操作符 ~ 用于将操作数的每一位取反。例如看这两个例子:

int a = 5; // 二进制表示为 00000101
int b = ~a; // b 的值为 -6(二进制表示为 11111010)
unsigned char num = 0b00001111;  // 15
unsigned char result = ~num;     // 0b11110000 → 240
(6)自增 ++ 和自减 --

自增操作符 ++ 用于将操作数的值增加1,而自减操作符 -- 用于将操作数的值减少1。这些操作符可以是前置或后置的。例如:

int a = 5;
int b = ++a; // 前置自增,a 的值变为 6,b 的值为 6
int c = a--; // 后置自减,c 的值为 6,a 的值变为 5
(7)解引用操作符 *

解引用操作符 * 用于访问指针所指向的内存地址中的值。例如:

int a = 10;
int *ptr = &a;
int b = *ptr; // b 的值为 10

我们和取地址结合一下举个例子:

int var = 42;
int *ptr = &var;  // ptr保存var的内存地址
int val = *ptr;   // val = 42(通过地址取值)

(8)强制类型转换(类型)

强制类型转换操作符(类型)用于将操作数转换为指定的数据类型。例如:

double a = 3.14;
int b = (int)a; // 将 double 类型转换为 int 类型,b 的值为 3
应用场景示例
#include <stdio.h>

int main() 
{
    int counter = 0;
    // 循环计数(后置自增)
    while (counter < 5) 
    {
        printf("%d ", counter++); // 输出: 0 1 2 3 4
    }
    
    // 指针遍历数组
    int arr[] = {10, 20, 30};
    int *p = arr;
    printf("\n%d", *p++);   // 输出10(先取*p,再p++)
    printf("\n%d", *(p));   // 输出20
}

提示:单目操作符在循环控制、指针操作、状态翻转等场景高频使用,但需严格遵循操作数单一性原则 

总结——关键注意事项

单目操作符是只需要一个操作数就能完成运算的操作符。在编程语言中,常见的单目操作符包括正号(+)、负号(-)、逻辑非(!)、按位取反(~)、自增(++)、自减(–)、取地址(&)、取值(*)、类型转换(如(int))等。例如,在C语言中:

int a = 10;
int b = -a;  // 使用负号单目操作符,b的值为-10
int c = !a;  // 使用逻辑非单目操作符,c的值为0(因为a非0,逻辑非后为假)
int d = ~a;  // 使用按位取反单目操作符,d的值为~10(二进制按位取反后的值)

展示一些主要的单目操作符——

#include <stdio.h>

int main() 
{
    int a = 10;
    int *p = &a; // 使用 & 获取 a 的地址

    printf("The value of a is: %d\n", a);
    printf("The address of a is: %p\n", (void*)&a); // 打印 a 的地址
    printf("The size of int is: %lu bytes\n", sizeof(int)); // 显示 int 类型的大小
    printf("The bitwise NOT of a is: %d\n", ~a); // 对 a 进行按位取反
    printf("The logical NOT of a is: %d\n", !a); // 对 a 进行逻辑非操作

    return 0;
}

关键注意事项:

(1)副作用控制
自增/自减会改变操作数本身,需警惕在复杂表达式中的副作用:

int i = 1;
int j = (i++) + (++i); // 未定义行为!结果不可预测[^3]

推荐拆分为独立语句:

i++;      // i=2
j = i++;  // j=2, i=3

(2)操作符优先级

单目操作符优先级通常高于算术操作符:

int k = 10;
int m = -k * 2;  // 等价于 (-k)*2 = -20

(3)类型一致性

自增/自减要求操作数为左值(如变量):

int *arr = malloc(10 * sizeof(int));
arr++;  // 合法:移动指针
// 5++; // 非法!常量不是左值
4、强制类型转换 

在编程中,强制类型转换(Explicit Type Conversion)是指程序员显式地将一种数据类型转换为另一种数据类型。这种转换通常用于表达式的值需要与变量的类型匹配的情况。以下是关于如何进行强制类型转换、常见问题及解决方法的详细说明。

#include<stdio.h>

int main()
{
	int a = (int)3.14;
	printf("%d\n", a);
	return 0;
}

这里我们把double类型的3.14强转成int:

3.14 --> 3

强制类型转换,即取浮点型的整数部分。

强制类型转换一般不要使用,所谓“强扭的瓜不甜”,我们不到万不得已不建议使用。

C语言的强制类型转换给大家推荐几篇文章:

猿享天开大佬的学懂C语言(三十一):C语言 强制类型转换

怀中猫ᝰ大佬的孤篇压全唐:C语言强制类型转换

C强制类型转换总结写的比较详实,可以借鉴一下。

还有总结了C语言和C++的强转的强制转换

强制类型转换的基本语法:

在 C/C++ 中,强制类型转换使用类型转换运算符(type)来完成。其基本形式如下:

(type) expression;

例如,像上面那样把3.14强转成3就是将一个int类型的值转换为double类型: 

int sum = 17, count = 5;
double mean = (double) sum / count; // 将 sum 转换为 double 类型再进行除法运算[^2]

强制类型转换的常见问题及解决方法:

(1)整数除法导致精度丢失

当两个整数相除时,结果会被截断为整数部分,这可能导致精度丢失。例如:

int sum = 17, count = 5;
double mean = sum / count; // 结果为 3.0,而不是期望的 3.4

解决方法:在进行除法之前,将其中一个操作数强制转换为浮点类型: 

double mean = (double) sum / count; // 正确的结果是 3.4[^2]
(2)指针类型转换带来的地址计算错误

在处理指针时,强制类型转换可能会导致地址计算错误。例如,&a+1和a+1的行为不同,前者是基于指针类型的加法,而后者是普通的数值加法。

int a = 0x001bfc18;
int *p = &a;
printf("%p\n", p + 1);       // 输出 0x001bfc1c(假设 int 占 4 字节)
printf("%p\n", &a + 1);      // 输出 0x001bfc28[^3]

解决方法:理解指针算术和普通数值算术的区别,避免对指针进行不恰当的类型转换。如果需要进行地址偏移,可以先将指针转换为char*类型,再进行偏移:

char *cp = (char *)&a;
cp += 1;
int *ip = (int *)cp;
(3)结构体或数组的强制类型转换导致未定义行为

当对结构体或数组进行强制类型转换时,如果目标类型与原始类型不兼容,可能会导致未定义行为。例如:

int a[10];
int *p = (int *)((char *)a + 1); // 将 a 的地址加上 1 后转换为 int*

此时,p指向的地址可能不是int类型的对齐地址,导致访问时出现未定义行为。

解决方法:确保转换后的指针指向的地址是对齐的。可以使用memcpy或者通过联合体(union)来安全地进行类型转换。

(4)浮点数到整数的转换导致截断

将浮点数转换为整数时,默认情况下会丢弃小数部分,只保留整数部分。例如:

double d = 3.9;
int i = (int)d; // i 的值为 3

解决方法:如果希望进行四舍五入,可以使用标准库函数如 round():

#include <math.h>
int i = (int)round(d); // i 的值为 4
(5)类型不匹配导致编译器警告或错误

在某些情况下,强制类型转换可能导致编译器发出警告或错误,尤其是在不同大小的指针类型之间转换时。

解决方法:使用更明确的类型转换方式,或者考虑重构代码以避免不必要的类型转换。例如,在 C++ 中可以使用static_cast、reinterpret_cast等更安全的转换方式。

以上这五点就是强制类型转换的常见问题及其解决方法了。


结尾

只要是主动学习,只要你有兴趣,只要你喜欢学,到处是时间。

往期回顾: 

【C语言】学习过程教训与经验杂谈:思想准备、知识回顾(四)

【C语言】学习过程教训与经验杂谈:思想准备、知识回顾(三)

【计算机语言选择规划】全是干货!从难度、就业、岗位选择、薪酬待遇、未来发展等方面详解第一门主流语言学习的选择

【C语言】学习过程教训与经验杂谈:思想准备、知识回顾(二)

【C语言】学习过程教训与经验杂谈:思想准备、知识回顾(一)

结语:本篇文章内容回顾到这里就结束了,希望对大家伙有所帮助。如果大家觉得文章有帮助的话,记得一键四连——点赞、收藏、关注、评论!谢谢uu们的支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值