变量的定义、声明、初始化、赋值

2822 2020-12-30 09:08

声明:告诉编译器或解析器该变量存在,这个行为并不分配内存空间,可以多次出现,只是告诉编译器有这么个对象。用于向程序表明变量的类型和名字。

extern int a;//纯声明(有extern关键字),不分配存储空间。

定义:只能出现一次,创建了一个对象,为对象分配内存空间。还可为变量指定初始值。定义也是声明,extern声明不是定义,extern通知编译器变量在其他地方被定义

int a;//声明+定义(无extern关键字),通常直接叫做定义。分配存储空间。

初始化:在定义变量以后,系统为变量分配的空间内存储的值是不确定的,所以需要对这个空间进行初始化,以确保程序的安全性和确定性,给变量赋默认值。

int a=1;//声明+定义+初始化,通常直接叫做初始化。分配存储空间。
extern int a=1;//声明+定义+初始化,通常直接叫做初始化。分配存储空间。

赋值:变量在分配空间之后的某个时间里,对变量的值进行刷新操作,即修改存储空间内的数据。

a=1;//修改已经定义好的变量a的值为1。不分配存储空间。

如何清晰的区分变量声明和定义

如果声明同时进行了初始化,就一定是定义,即使前面加了extern。
只有当extern声明位于函数外部时,才可以被初始化。

赋值是变量运行过程中获取的新值。

说明

区别变量声明和定义的方法:

声明:含有extern关键字且变量没有初始化,不分配存储空间。

定义(初始化):不含extern关键字或者含有extern关键字但是变量被初始化,分配存储空间。

变量可以声明多次;但只能定义一次(一个变量只能在一个源文件中定义)
声明通常放在头文件(.h)中;定义放在源文件(.cpp)中,防止文件被多次引用,重复定义。

 

Q:空指针、野指针、变量定义、声明、赋值

A:

空指针
  • 定义 :空指针是一个特殊的指针值,用来指示该指针没有指向任何有效的内存地址。在不同的编程语言中有不同的表示方式。例如,在 C 和 C ++ 中,通常用宏 NULL(其值一般为 0)来表示空指针。在 Java 中,用 null 关键字表示空指针。
  • 示例
    • 在 C 语言中:
    • c
       
  • 复制
    int *ptr = NULL;  // 定义一个指向整数的空指针
     
  • 在 Java 中:
  • java
     
      • 复制
        String str = null;  // 定义一个指向字符串的空指针
         
    • 应用场景 :空指针可以用于初始化指针变量,表示该指针目前没有指向有效的对象或内存位置。这有助于避免野指针(后面会介绍)带来的问题。例如,在函数返回一个指针时,如果无法成功分配内存或者没有合适的对象可以返回,可以返回空指针来表明这种情况。
  • 野指针
    • 定义 :野指针是指指向不可知内存地址的指针。也就是说,这个指针变量存储的地址不是程序有意让它指向的有效地址,并且这个地址上的内容也没有被程序有意分配给该指针所指向的类型的数据。野指针的产生可能是由于指针没有被正确初始化,或者是指针在使用后没有被适当设置为空指针,或者是由于指针操作越界等错误操作导致的。
    • 示例
      • 在 C 语言中:
      • c
         
      • 复制
        int *ptr;  // 定义了一个指针,但没有初始化,此时 ptr 是一个野指针
        // 错误地使用野指针
        printf("%d", *ptr);  // 这里访问野指针指向的内容可能会导致程序崩溃或者读取到垃圾值
         
    • 危害 :野指针的危险在于它可能会访问非法内存地址,从而导致程序崩溃、数据损坏等不可预测的错误。例如,当野指针试图修改它所指向的非法内存地址的内容时,可能会破坏操作系统的内存管理或者系统的其他关键数据,进而导致整个系统不稳定。
  • 变量定义
    • 定义 :变量定义是指为变量分配内存空间并指定其数据类型的操作。在定义变量时,编译器会根据变量的数据类型分配相应大小的内存块,并且可以为变量赋予一个初始值。
    • 示例
      • 在 C 语言中:
      • c
         
  • 复制
    int age = 20;  // 定义了一个整型变量 age,并为其赋初值 20
    char gender = 'M';  // 定义了一个字符型变量 gender,并赋初值 'M'
     
  • 在 Python 中:
  • Python
     
      • 复制
        name = "Alice"  # 定义了一个字符串变量 name,赋值为 "Alice"
        num = 100  # 定义了一个整数变量 num,赋值为 100
         
    • 作用 :变量定义是程序能够使用变量的前提。通过定义变量,程序可以在内存中有一个存储位置来保存数据,并且可以通过变量名来访问和操作这些数据。合理的变量定义(包括数据类型的选择和初始值的设置)对于程序的正确运行和性能优化都非常重要。
  • 变量声明
    • 定义 :变量声明是向编译器告知变量的名称和数据类型,但不一定为变量分配内存空间。它主要是在编译阶段让编译器知道变量的存在,以便在后续的代码中能够正确地识别和使用该变量。在某些编程语言(如 C 和 C ++)中,变量可以先声明后定义。
    • 示例
      • 在 C 语言中:
      • c
         
      • 复制
        extern int value;  // 声明一个外部整型变量 value,此时没有分配内存空间
        // 在其他文件中定义 value
        int value = 10;  // 定义变量 value 并赋初值 10
         
    • 作用 :变量声明可以在不同的文件或者代码模块之间共享变量信息。例如,在大型项目中,当一个变量需要在多个源文件中使用时,可以在一个文件中定义该变量,在其他文件中通过声明来告知编译器该变量的存在,从而实现变量的跨文件访问。
  • 赋值
    • 定义 :赋值是将一个值赋予变量或者内存位置的操作。赋值操作通常使用赋值运算符(如等号 “=”)来完成。赋值可以是在变量定义时同时进行,也可以是在变量定义之后根据程序逻辑的需要来改变变量的值。
    • 示例
      • 在 Java 中:
      • java
         
  • 复制
    int count;  // 定义变量 count
    count = 5;  // 将 5 赋值给 count
    count = count + 3;  // 将 count 的值加 3 后重新赋值给 count,此时 count 的值为 8
     
  • 在 JavaScript 中:
  • JavaScript
     
    • 复制
      let score;  // 定义变量 score
      score = 90;  // 赋值给 score
      score = score * 0.8;  // 重新赋值,score 的值变为 72
       
  • 作用 :赋值操作是程序动态改变数据状态的主要方式。通过赋值,程序可以根据用户输入、计算结果、与其他程序或系统的交互等情况来更新变量的值,从而实现程序的逻辑功能,如计算累加和、更新游戏得分等。
 

Q:变量声明和定义有什么区别?

A:

变量声明和定义是编程中两个重要但不同的概念,它们的区别主要体现在以下几个方面:

1. 定义

  • 变量声明:是指向编译器告知变量的名称和数据类型,但不一定为变量分配内存空间。它主要是在编译阶段让编译器知道变量的存在,以便在后续的代码中能够正确地识别和使用该变量。
  • 变量定义:是指为变量分配内存空间并指定其数据类型的操作。在定义变量时,编译器会根据变量的数据类型分配相应大小的内存块,并且可以为变量赋予一个初始值。

2. 作用

  • 变量声明:主要用于在不同的文件或者代码模块之间共享变量信息。例如,在大型项目中,当一个变量需要在多个源文件中使用时,可以在一个文件中定义该变量,在其他文件中通过声明来告知编译器该变量的存在,从而实现变量的跨文件访问。
  • 变量定义:是程序能够使用变量的前提。通过定义变量,程序可以在内存中有一个存储位置来保存数据,并且可以通过变量名来访问和操作这些数据。合理的变量定义(包括数据类型的选择和初始值的设置)对于程序的正确运行和性能优化都非常重要。

3. 出现的位置

  • 变量声明:通常出现在代码的开头部分,或者在使用变量之前。在 C 和 C ++ 中,变量可以先声明后定义,声明通常出现在文件的顶部或者函数的开头。
  • 变量定义:通常出现在代码中变量第一次被使用的地方,或者在程序的初始化部分。在定义变量时,可以同时为其赋初值。

4. 示例

  • C 语言中的变量声明和定义
    • 声明
    c
     
复制
extern int value;  // 声明一个外部整型变量 value,此时没有分配内存空间
 
  • 定义
c
 
  • 复制
    int value = 10;  // 定义变量 value 并赋初值 10
     
  • C++ 中的变量声明和定义
    • 声明
    cpp
     
复制
class MyClass;  // 声明一个类 MyClass,但没有定义其内容
 
  • 定义
cpp
 
  • 复制
    class MyClass {
        int x;  // 定义类中的成员变量 x
    public:
        void setX(int val) { x = val; }  // 定义类中的成员函数 setX
    };
     
  • Java 中的变量声明和定义
    • 声明
    java
     
复制
public class Main {
    static int value;  // 声明一个静态整型变量 value,此时会分配内存空间并初始化为 0
}
 
  • 定义
java
 
  • 复制
    public class Main {
        public static void main(String[] args) {
            int num;  // 声明变量 num
            num = 5;  // 定义变量 num 并赋值为 5
        }
    }
     
  • Python 中的变量声明和定义
    • Python 中没有显式的变量声明,变量在赋值时自动定义。例如:
    Python
     
  • 复制
    name = "Alice"  # 定义了一个字符串变量 name,赋值为 "Alice"
    num = 100       # 定义了一个整数变量 num,赋值为 100
     

总结对比表格

表格
 
复制
特性 变量声明 变量定义
分配内存空间 不一定分配内存空间 分配内存空间
初始化 不一定初始化 可以初始化
出现位置 通常在代码开头或使用变量之前 通常在变量第一次被使用的地方
作用 告知编译器变量的存在 为变量分配内存并可以初始化
跨文件访问 支持跨文件访问(如 C/C++ 的 extern) 一般在单个文件内有效
通过以上的对比和示例,可以更清晰地理解变量声明和定义的区别。
 

Q:java变量什么情况下声明一定要紧跟定义?

A:

在 Java 中,变量声明和定义通常可以分开,但在某些情况下,声明一定要紧跟定义。以下是这些情况:

1. 局部变量

  • 在 Java 中,局部变量(定义在方法内部的变量)必须先声明并定义,然后才能使用。否则,编译器会报错。
  • 原因:局部变量没有默认值,必须显式初始化。
  • 示例
    java
     
  • 复制
    public class Main {
        public static void main(String[] args) {
            int num;  // 声明局部变量 num
            // System.out.println(num);  // 错误:num 未初始化
            num = 5;  // 定义 num
            System.out.println(num);  // 输出 5
        }
    }
     

2. 匿名类中的变量

  • 在匿名类中,如果需要访问外部方法的局部变量,这些变量必须是 final 或者是 effectively final(即在逻辑上是 final,但不需要显式声明为 final)。
  • 原因:匿名类的生命周期可能超过外部方法的执行时间,因此需要确保变量的值不会在方法执行后被修改。
  • 示例
    java
     
  • 复制
    public class Main {
        public static void main(String[] args) {
            final int num = 10;  // 声明并定义 num 为 final
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    System.out.println(num);  // 访问 num
                }
            };
            r.run();  // 输出 10
        }
    }
     

3. Lambda 表达式中的变量

  • 在 Lambda 表达式中,如果需要访问外部方法的局部变量,这些变量也必须是 final 或者是 effectively final
  • 原因:与匿名类类似,Lambda 表达式的生命周期可能超过外部方法的执行时间。
  • 示例
    java
     
  • 复制
    public class Main {
        public static void main(String[] args) {
            int num = 20;  // 声明并定义 num 为 effectively final
            Runnable r = () -> System.out.println(num);  // 访问 num
            r.run();  // 输出 20
        }
    }
     

4. 枚举中的常量

  • 在枚举中,枚举常量的声明和定义必须同时进行。
  • 原因:枚举常量是编译时常量,必须在声明时初始化。
  • 示例
    java
     
  • 复制
    public enum Color {
        RED("红色"),  // 声明并定义枚举常量 RED
        GREEN("绿色"),  // 声明并定义枚举常量 GREEN
        BLUE("蓝色");  // 声明并定义枚举常量 BLUE
    
        private final String description;
    
        Color(String description) {
            this.description = description;
        }
    
        public String getDescription() {
            return description;
        }
    }
     

5. 实例变量和类变量的特殊情况

  • 实例变量和类变量可以声明后单独定义,但在某些情况下,声明和定义必须同时进行,例如:
    • 如果变量是 final 的。
    • 如果变量是 static final 的(即编译时常量)。
  • 原因final 变量必须在声明时初始化,或者在构造函数中初始化。
  • 示例
    java
     
  • 复制
    public class Main {
        private final int num1 = 10;  // 声明并定义 num1
        private static final int num2 = 20;  // 声明并定义 num2
    
        public Main(int num3) {
            this.num3 = num3;  // 在构造函数中定义 num3
        }
    
        private final int num3;  // 声明 num3,必须在构造函数中定义
    }
     

总结

在 Java 中,变量声明和定义需要同时进行的情况主要包括:
  • 局部变量必须先声明并定义才能使用。
  • 匿名类和 Lambda 表达式中访问的局部变量必须是 finaleffectively final,通常声明和定义同时进行。
  • 枚举常量必须在声明时初始化。
  • final 变量(尤其是编译时常量)必须在声明时初始化。
这些规则确保了变量的值在使用时是确定的,避免了潜在的逻辑错误。

全部评论

·