C/C++ 学习笔记二(变量、表达式)

变量

计算机中变量是一个标识符或者名称。

在计算机中提供给变量两个信息

  1. 变量地址 ,操作系统给变量分配的若干内存的首地址
  2. 变量的值 ,内存单元中存放的数据

从变量的存储位置进行区分,可分为 内存CPU的寄存器 两类

从变量的生命周期进行区分,变量分为静态动态存储两种

静态存储 存储在内存的静态存储区,编译时就分配了存储空间,在运行期间有固定的存储单元,程序结束后,才会释放。

动态存储 存储在动态存储区中,只有变量所在的函数被调用时,才会临时分配一段,程序调用结束后,空间便会释放。

而在C语言提供4种存储类型

1.auto 自动 2.static 静态 3.register 寄存器 4.extern 外部

外部变量和内部变量的区别 ?

外部、内部变量的区别十分简单,内部变量指的是函数内的变量,函数外的变量便是外部变量(全局变量)。 外部变量可以被其他文件所使用,他的存储方式是静态存储,它的生命周期等同于整个程序(static 对象 ,全局变量)。 而内部变量仅能被作用域内访问,他存储方式是动态存储,它生命周期在超出作用域后会被回收。(auto对象)

全局变量和静态变量的区别 ?

在C语言中,可以使用static声明一个静态变量,也可以在函数外声明一个全局变量,其他文件使用extern对该变量进行访问。他们两者的存储方式都是使用静态存储方式,存储在内存的静态存储区。

他们之前的差别在于 全局变量的作用域是整个程序。(跨文件) 而静态变量的作用域则是当前源文件,其他源文件不可访问。

说到这,即extern 不可以用来修饰 static,因为他们两者思想便是冲突的(extern 用于跨源文件,static用于限制变量在当前源文件中使用)。

他们的作用正好相反。

extern 的作用是用于多文件数据共享

static 的作则是用于数据隔离

例如如下

//global.c
#include <stdio.h>
int gloablValue =2;
static int staticVal = 12;
void testFunc()
{
    printf("static value is %d",staticVal);
}
//main.c
#include <stdio.h>
#include "global.c"
extern int gloablValue;
int main(){
    printf("gloablValue %d  \n",gloablValue);
    return 0;
}

const 其实不是常量!

C语言中经常会使用const 修饰符,限定一个变量不允许被改变。防止意外的修改。 但是const 变量经常会被是常量,其实 const 变量是只读变量,不是常量。

下面的例子证明const 并不是常量。 运行下面代码会报错。因为指定数组大小时应该使用的是常量

   const int const_array_num = 10;
   int arr[const_array_num] = 12;

既然const 修饰的不是常量,那const 变量能否被修改?

下面的代码访问了num的指向的内存区域,并且修改了他的值

   const int num = 100;
   int * p = (int *)&num;
   int * p2 = p;
   *p = 1;
   printf("num = %d  *p = %d  *p2 = %d \n",num,*p,*p2);
   printf("*num = %p, p = %p , p2 = %p \n",&num,p,p2);

下面是输出的结果

num = 100  *p = 1  *p2 = 1 
*num = 0x7fff5fbff728, p = 0x7fff5fbff728 , p2 = 0x7fff5fbff728

可以看到三者打印的指针是一样,但num打印的值依然是100,其实const修饰的值读取的是数据段,通过指针读取的数据保存在堆栈段。

const其实提供了一种保护机制,保证变量只能从数据段中读取数据,确保了他不被改变。

表达式

表达式是由常量、变量、函数和运算符构成的。运算符大致分为算术表达式、关系表达式、逻辑表达式、赋值表达式、条件表达式和逗号表达式等。因C语言表达式语法灵活,很有必要为提高程序可读性,在开发时遵循一些改善的建议。

ARM机器上减少使用除法与求模运算

ARM硬件上不支持除法运算,编译器调用C库的函数来实现除法运算,如需要除法运算中是程序中的瓶颈所在,可以通过减少除法运行来进行优化。

避免相似的操作符混淆

避免 = 与 == 混淆

开发时,常用到 == 与整型数据进行判断,这种情况下,如果漏写一个=会容易导致逻辑出现问题

如下例子,a=1由于写少了一个=,导致语句永远也无法走到else条件中。

 int a = 123;
 if(a=1){
   //do something
 }else{
 }

解决的办法是将对比常量提前,若少写=时,编译器便会提前报错,这样可以在一定程度上避免误写的发生。

 int a = 123;
 if(1==a){
   //do something
 }else{
 }

避免使用复杂的复合表达式

开发过程中应该避免使用复杂的表达式 如下方的例子,应该尽量避免

int a = 10;
a+=a-1=a*=a;
printf("%d\n",a);

if else 语句无论子语句多少,都应使用{}包括

形如如下的if else语句不使用{}包含时经常会让后来的代码维护者读代码时十分头疼.

if(a>0)
    b = 1;
    if(a > 100)
        b = 100;
else
    b= 0;

正确做法,为每个if 、else 加上对应的{}。这样会让代码更加清晰。

if(a>0){
    b = 1;
    if(a > 100){
        b = 100;
    }
}
else{
    b= 0;
}

for循环中尽量将逻辑判断语句置于循环外层

如极限情况下例子会执行2*n次判断

for(int i = 0; i<n ; i++)
{
    if(condition)
    {
        DoSomething();
    }else{
        DoOtherthing();
    }
}

以下判断语句置于外层时,极限情况下减少n-1次。当for循环次数很大时,这样的小优化是值得的。

if(condition)
{
    for(int i = 0; i<n ; i++)
    {
        DoSomething();
    }
}
else
{
    for(int i = 0; i<n ; i++)
    {
        DoOtherthing();
    }
}

注意typedef与#define的使用

typedef 是一种类型的新别名, 而宏是简单字符串替换

宏定义的作用时间是在 预处理阶段

typedef 的作用时间是在 编译阶段

在使用宏定义期望替换类型时,切记不可同一行类声明两个变量

 typedef char * PCHAR1;
 #define char * PCHAR2;
 PCHAR1 c1,c2;
 PCHAR2 c3,c4;
//预处理后
typedef char * PCHAR1;
PCHAR1 c1,c2;
char * c3,c4;

此时c1,c2的类型均是char 此时c3 类型是 char 而 c4的类型是char

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

深入分析golang多值返回以及闭包的实现

一、前言 golang有很多新颖的特性,不知道大家的使用的时候,有没想过,这些特性是如何实现的?当然你可能会说,不了解这些特性好像也不影响自己使用golang,...

3736
来自专栏星回的实验室

js重修课[二]:表达式和运算符

681
来自专栏Vamei实验室

Python基础06 循环

循环用于重复执行一些程序块。从上一讲的选择结构,我们已经看到了如何用缩进来表示程序块的隶属关系。循环也会用到类似的写法。 for循环 for循环需要预先设定好循...

1826
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(八) ——Redis列表对象和哈希对象实现原理

《Redis设计与实现》读书笔记(八) ——Redis列表对象和哈希对象实现原理 (原创内容,转载请注明来源,谢谢) 一、列表对象 列表对象的编码可以是zipl...

3567
来自专栏java学习

Java每日一练(2017/8/21)

每日一句 学的到东西的事情是锻炼,学不到的是磨练。 查看以前的所有练习题目以及答案:https://mp.weixin.qq.com/mp/homepage?_...

33716
来自专栏java一日一条

Java中关于String类型的10个问题

简单来说,“==”是用来检测俩引用是不是指向内存中的同一个对象,而equals()方法则检测的是两个对象的值是否相等。只要你想检测俩字符串是不是相等的,你就必须...

401
来自专栏老九学堂

这是谁做的作业!C语言编码太不规范了...

1) 程序应采用缩进风格编写,每层缩进使用一个制表位(TAB),类定义、方法都应顶格书写;

1282
来自专栏IT可乐

Redis详解(五)------ redis的五大数据类型实现原理

  前面两篇博客,第一篇介绍了五大数据类型的基本用法,第二篇介绍了Redis底层的六种数据结构。在Redis中,并没有直接使用这些数据结构来实现键值对数据库,而...

630
来自专栏swag code

Java中的private、protected、public和default的区别(详解)

(1)对于public修饰符,它具有最大的访问权限,可以访问任何一个在CLASSPATH下的类、接口、异常等。它往往用于对外的情况,也就是对象或类对外的一种接口...

553
来自专栏玄魂工作室

《改善C程序代码的125个建议》-防止整数类型产生回绕与溢出

以下内容摘抄自《改善C程序代码的125个建议》: 建议2:防止整数类型产生回绕与溢出 到C99为止,C语言为我们提供了12个相关的数据类型关键字来表达各种数据...

2787

扫码关注云+社区