达内C语言学习(day08)

每日英语:

建议全局变量名以g_开头,g = global:全局

static:静态

dynamic:动态

pointer:指针

回顾:

1. 二维数组

  1. 二维数组本身还是一维数组,做了分组而已,搞成了I行J列

  2. 定义二维数组的语法:数据类型 数组名[I] [J] = {初始值}

    瞬间脑子实现二维数组的内存分布图

  3. 定义二维数组的形式

  4. 二维数组公式

    a = a[0] = &a[0][0]
    各种sizeof
    

2. 函数

  1. 函数功能:语句的组合,具有独立性和通用性

  2. 函数的使用3步骤:

    函数声明:extern 返回值 数据类型 / void 函数名(形参表)

    函数定义:

    返回值数据类型/void  函数名(形参表/void) {
    	函数体语句;
    	returnreturn 数值/不需要
    }
    

    函数调用:变量 = 函数名(实参表/空);

  3. 函数使用的4种形式:

    无参无返回值/有参无返回值/无参有返回值/有参有返回值

    记住:swap经典代码案例

  4. 函数和数组的关系

    编程公式:

    返回值数据类型/void 函数名(数组首地址(int a[]), 其余形参参数自行添加定义) {
    	a[元素下标];  // 获取元素值
    	a[元素下标] = 新值: // 修改元素值
    }  // 此函数可以直接通过首地址a修改访问数组内存!
    

作业:

编写两个函数实现将数组中某个元素的某个bit位清0或者置1

参考代码:bit.c

/*函数那点事*/
#include <stdio.h>

/*声明打印函数print,清0clear_bit, 置1set_bit */
extern void print(int a[], int index, int len);
extern void clear_bit(int a[], int index, int bit, int len1); // bit 位编号
extern void set_bit(int a[], int index, int bit, int len2);

int main(void) {
	int a[2] = {0x55, 0xaa};
	int len = sizeof(a) / sizeof(a[0]);
	int len1 = sizeof(a) / sizeof(a[0]);
	int len2 = sizeof(a) /sizeof(a[0]);

	//清0
	clear_bit(a, 0, 0, len1);  // 调用clear_bit函数
	print(a, 0, len);
	clear_bit(a , 1, 1, len1);
	print(a, 1, len);
	print(a, 2 ,len);

	//置1
	set_bit(a, 0, 0, len2);  // 调用set_bit函数
	print(a, 0, len);
	set_bit(a, 1, 1, len2);
	print(a, 1, len);

	return 0;
}

/*定义print,clear_bit,set_bit*/
void print(int a[], int index, int len) {
	if(index >= len) {   // 添加安全保护,防止越界访问
		printf("所取元素小标超出范围\n");
	}
	printf("数组的%d个元素是:%#x\n", index, a[index]);
}

void clear_bit(int a[], int index, int bit, int len1) {
	if(index >= len1) {
		printf("所取得第%d个元素超出范围\n", index);
	}
	a[index] &= ~(1 << bit);
}

void set_bit(int a[], int index, int bit, int len2) {
		if(index >= len2) {
		printf("所取得第%d个元素超出范围\n", index);
	}
	a[index] |= (1 << bit);
}
结果:
数组的0个元素是:0x54
数组的1个元素是:0xa8
所取元素小标超出范围
数组的2个元素是:0x2
数组的0个元素是:0x55
数组的1个元素是:0xaa

第八课:变量(包括数组)作用域和可见性

1. 明确

  1. c语言变量按照数据类型(占内存大小)分:12种(char, short,…double)

2. C语言变量按照作用域和可见性分:

局部变量和全局变量

3. 局部变量

定义在函数内部的变量

例如:

void A(void) {
	int a = 250;///局部变量
}

注意:局部变量如果不初始化gcc会给一个款七八糟的随机数

4. 全局变量

定义在函数之外的变量

int g_a = 250; 全局变量
void A(void) {
	int a = 250;  // 局部变量
}
int g_b = 250;  //全局变量

注意:全局变量不初始化,gcc一律给0

5. static关键字特性

如果定义变量时,前面加static关键字修饰,此变量又称静态变量

如果定义变量前面,不加static’关键字修饰,此变量又称非静态变量

例如:

static int a = 250; //静态变量
int a = 250;// 非静态变量

6. 终极结论:

C语言变量最终分为4类:

局部非静态变量/局部静态变量/全局非静态变量/全局静态变量

7. 详解局部非静态变量特点:

7.1 形式1

void A(void) {
	printf("%d\n", a);  // 不可以,gcc报错,变量a没有定义的错误
	int a = 250;   // 局部非静态变量
	printf("%d\n", a);
}

7.2 形式2

viod A(void) {
	if(1 == 1) {
		int a = 250;
		printf("%d\n", a); //可以
	}
	printf("%d\n", a);  // 不可以,gcc报错
}

7.3 函数的形参

void A(int a) {	//a在整个函数体内部都可以访问,但是出了函数就不能再访问了
	printf("%d\n", a);
}
参考代码:var.c

7.4 切记:局部非静态变量特点

  1. 此类变量使用范围(访问范围):从定义开始一次向下知道最近的花括号结束

  2. 此类变量分配的内存生命周期:从定义的地方开始操作系统就会给变量分配内存

    ​ 直到最近的花括号操作系统立马收回给变量分配的内存

    ​ 只能的等下一次调用或者运行操作系统继续给变量分配内存

8. 局部静态变量特点(堪称钉子户)

8.1 形式1

void A(void) {
	printf("%d\n", a);  // 不可以,gcc报错,变量a没有定义的错误
	static int a = 250;   // 局部非静态变量
	printf("%d\n", a);
}

8.2 形式2

viod A(void) {
	if(1 == 1) {
		static int a = 250;
		printf("%d\n", a); //可以
	}
	printf("%d\n", a);  // 不可以,gcc报错
}
参考代码:var.c
/*局部非静态变量演示*/
#include <stdio.h>

/*定义一个A函数*/
void A(void)
{
    static int a = 250; // 定义静态变量,钉子户
    printf("A函数:a = %d\n", a);
    a = 10;    // 执行完一次A函数后,它的生命周期不会结束,还在内存中,所以第二次调用A函数就打印10
}


int main(void)
{
    // 局部非静态变量
    // printf("a = %d\n", a);
    int a = 250; //局部非静态变量
    printf("a = %d\n", a);

    if(520 == a) {
        int b = 520;
        printf("b = %d\n", b);  // 可以
    }
    // printf("b = %d\n", b);   // 不可以 报错

    // 局部静态变量演示
    A();
    A();

    return 0;
}

结果:
a = 250      
A函数:a = 250
A函数:a = 10

8.3 切记:局部静态变量特点

  1. 此类变量使用范围(访问范围):从定义开始一次向下知道最近的花括号结束

  2. 此类变量分配的生存周期:从程序运行时操作系统给变量分配内存,知道程序结束,

    ​ 操作系统才会收回变量的内存,一次分配,终身使用

9. 详解全局非静态变量特点

9.1 形式1

全局非静态变量的定义和使用访问都是在同一个源文件中进行

例如:

vim var1.c

void B(void)
{
	printf("g_a = %d\n", g_a);  //不可以访问,gcc会报g_a没有定义的错误
}

int g_a = 250;  // 全局非静态变量

void A(void)
{
    // 访问使用
	printf("g_a = %d\n", g_a);  //可以访问
}
参考代码:var1.c
/*全局非静态变量*/
#include <stdio.h>
void C(void)
{
    //g_a--;  // gcc报错
}
int g_a = 250;
void A(void)
{
    printf("A函数:%d\n", g_a);  // 正常访问
}
void B(void)
{
    g_a++;   // 正常访问
}
void D(void)
{
    g_a--;  // 正常访问
} 
int main(void)
{
    A();
    B();
    A();
    D();
    A();
    return 0;
}
结果:
A函数:250
A函数:251
A函数:250

9.2 形式2

全局非静态变量定义和访问使用在不同源文件中进行(又称跨文件访问)

切记:如果一个源文件定义一个全局非静态变量,另一个源文件要想直接访问使用这个全局变量

​ 例如:打印它的值或修改它的值

​ 此时要求访问使用全局变量的文件必须声明这个全局非静态变量

​ 声明全局非静态变量语法:extern 数据类型 全局非静态变量名; // 不要给初值

​ 声明完毕,方可访问定义的全局变量

​ 注意:声明是不会分配内存的

参考代码:var2.c(负责定义全局非静态变量) var3.c(负责访问使用全局非静态变量)

编译命令:gcc -o var2 var2.c var3.c // 将var2.c var3.c编译生成一个可执行文件

运行./var2

var2.c

/*全局非静态变量跨文件访问演示:此文件只负责定义全局非静态变量*/
#include <stdio.h> // 为了使用printf函数

/*定义全局非静态变量*/
int g_a = 250;

/*定义打印函数print*/
void print(void)
{
    printf("print函数:g_a = %d\n", g_a);
}

/*定义自增函数*/
void inc_var(void)
{
    g_a++;
}
var3.c

/*全局非静态变量跨文件访问演示:此文件只负责访问全局非静态变量*/
#include <stdio.h>

/*声明全局非静态函数*/
extern int g_a;
/*声明打印函数print,自增函数inc_var*/
extern void print(void);
extern void inc_var(void);

/*定义此文件里的自减函数*/
void dec_var(void)
{
    g_a--;  // 可以访问
}

int main(void)
{
    print();  //250
    inc_var(); 
    print(); //251
    dec_var();
    printf("main函数里的自减函数:g_a = %d\n", g_a); //250
    return 0;
}

结果:

print函数:g_a = 250
print函数:g_a = 251
main函数里的自减函数:g_a = 250

9.3 切记:全局非静态变量特点

  1. 此类变量使用范围:分两种情况:

    1. 如果是在定义变量的源文件中,范围从定义的地方开始一次向下所有的函数都可以访问,前面的函数无权访问

    2. 如果是在不同文件(跨文件)访问,范围是从声明的地方开始一次向下所有的函数都可以访问

      声明之前的函数无权访问

  2. 此类变量分配的内存生命周期:从启动运行程序开始操作系统为其分配内存

    ​ 知道程序结束,操作系统才会收回变量的内存

  3. 实际开发建议:全局非静态变量要少用,慎用,能不用最好不用

    ​ 负责极易出现乱序访问的严重后果

    ​ 如果非要使用,一定要记得用互斥保护的方法,来保护全局非静态变量

    ​ 阻止乱序发生,但是这种互斥保护会降低代码的执行效率

    ​ 注意:互斥机制等第二阶段课程详解

10. 全局静态变量

10.1 形式:

全局静态变量的定义和使用访问,永远只能在同一个文件中进行,不可跨文件访问,

也就是说全局静态变量只能用于本文件,其他源文件访问不了

参考代码:var2.c var3.c

编译:gcc -o var2 var2.c var3.c

运行: ./var2

10.2 切记:全局变量的特点

  1. 此类变量使用范围:只能用于定义变量所在的文件,不能跨文件访问,并且从定义的地方开始,依次向下所有的函数,都可以访问

  2. 此类变量分配的内存生命周期:从启动运行程序开始操作系统为其分配内存

    ​ 直到程序结束,操作系统才会收回变量的内存

  3. 实际开发建议:全局非静态变量要少用,慎用,能不用最好不用

    ​ 否则极易出现乱序访问的严重后果,只是它发生乱序的概率,比全局非静态变量要低

    ​ 如果非要使用,一定要记得用互斥保护的方法,来保护全局非静态变量

    ​ 阻止乱序发生,但是这种互斥保护会降低代码的执行效率

    ​ 注意:互斥机制等第二阶段课程详解

11. static终极总结(笔试题必考)

  1. static修饰的全局变量只能用于本文件,其他文件不能访问该全局变量

    例如:static int g_b = 520;

  2. static修饰的函数(在定义函数的时候进行修饰)统同样只能用于本文件的其他函数调用

    其他文件不能访问调用此函数

    例如:

    vim static1.c
    
    static int add(int x, int y);
    {
    	return x + y;
    }
    int main(void)
    {
    	add(10,20);  // 可以
    	return 0;
    }
    
    vim static2.c
    extern int add(int, int); // 报错
    int test(void)
    {
    	add(100, 200);  // 不能调用,报错
    }
    
    1. static修饰的变量或者函数将来使用起来相对不修饰安全点,某种程度上可以降低乱序发生的概率,多多少少起到了间接保护的作用
参考代码:var2.c var3.c
var2.c
/*全局非静态变量跨文件访问演示:此文件只负责定义全局非静态变量*/
#include <stdio.h> // 为了使用printf函数

/*定义全局非静态变量*/
int g_a = 250;

/*定义全局静态变量*/
static int g_b = 520;
/*定义静态函数:用static修饰的函数*/
static void print1(void)
{
    printf("测试static修饰的函数调用关系\n");
}

/*定义打印函数print*/
void print(void)
{
    printf("print函数:g_a = %d\n", g_a);
    printf("print函数:g_b = %d\n", g_b);
    print1(); // 同文件中调用静态函数
}

/*定义自增函数*/
void inc_var(void)
{
    g_a++;
    g_b++;
}

var3.c

/*全局变量跨文件访问演示:此文件只负责访问全局非静态变量*/
#include <stdio.h>

/*声明全局函数*/
extern int g_a;
// extern int g_b;  报错

/*声明打印函数print,自增函数inc_var*/
extern void print(void);
extern void inc_var(void);

/*声明静态函数*/
// extern void print1(void);    // 报错 error: ld returned 1 exit status

/*定义此文件里的自减函数*/
void dec_var(void)
{
    g_a--;  // 可以访问
}

int main(void)
{
    print();  //250
    inc_var(); ``
    print(); //251
    dec_var();
    printf("main函数里的自减函数:g_a = %d\n", g_a); //250
    // printf("main函数里的自减函数:g_b = %d\n", g_b);  报错
    // print1();  // 报错
    return 0;
}

结果:

print函数:g_a = 250
print函数:g_b = 520
测试static修饰的函数调用关系
print函数:g_a = 251
print函数:g_b = 521
测试static修饰的函数调用关系

12. 全局变量乱序分析:

例如:

// 定义全局变量
int g_a;
// 自增操作
g_a++;
明确cpu做g_a++数据运算,实际微观上CPU要经过三步骤运算:
第一步:先从内存中将变量g_a的值读取到CPU内部
第二步:然后在CPU内部做加1操作
第三部:最后将CPU内部的运算结果保存到内存中
具体参见:全局变量乱序.png

在这里插入图片描述

明确:由于linux系统是一个多任务系统,也就是宏观上可以同时运行多个程序(别名:线程(thread))

​ 程序要想运行必须先获取到CPU,没有CPU无法运行

​ 关键是程序之间还存在优先级,也就是高优先级的程序,抢夺CPU资源的能力

例如:比如A程序正在运行(CPU正在给A用),突然来了个B程序,它的优先级高于A

​ 所以B不带商量的将A的CPU抢夺走,A就停止运行,B开始投入运行,B运行完毕然后将CPU再

​ 归还给A程序,A继续接着运行(不是从头再来一遍)

乱序产生:假设现在有个A程序做以下代码:

for(int i = 0; i < 10000; i++)
	g_a++;
// 对g_a加10000次,心里要明白,实际CPU执行这条语句要经过三步骤
第一步:先从内存中将变量g_a的值读取到CPU内部
第二步:然后在CPU内部做加1操作
第三部:最后将CPU内部的运算结果保存到内存中

当A程序假设正在处理第50次加1操作,刚执行完第一步,就在此时此刻高优先级的B程序运行了,B程序毫无条件的抢夺A程序的CPU资源,A就停止第二步和第三步运行

B程序接着运行以下代码

for(int i = 0; i < 10000; i++)
	g_a++; 

等B执行完1万次加1操作之后,此时B程序将CPU资源归还给A,A继续运行,本来A应该做完第50次加1

而此过程少了一次,此过程如果频繁的发生A和B的切换,将来g_a理论上可以做2万次加1,而实际上肯定少于1万次

参考代码:thread.c


第九课:指针(C语言灵魂)

1. 指针的定义:

指针本质就是一个变量,而这个变量永远只能存储内存地址(编号)

所以此变量对应的专业术语叫指针变量(简称指针)

结论:将来通过指针变量保存的地址就可以对这块内存区域进行任意访问

​ 可以读内存数据还可以修改内存数据

2. 指针变量定义的语法格式

2.1 书写形式1

数据类型 * 指针变量名;
例如:
int * pa; // 定义指针变量pa

2.2 书写形式2

数据类型* 指针变量名;
例如:
int* pa; // 定义指针变量pa 

2.3 书写形式3

数据类型 *指针变量名;
例如:
int *pa;  //定义指针变量pa

语义:

都是在定义指针变量pa,将来这个变量pa能够保存一块内存区域的首地址

也就是指针变量pa本身也会分配内存,只是它对应的内存用来存储其他内存区域的首地址

此过程简称pa指向某块内存区域

并且指针变量保存的首地址对应的内存区域保存着一个int类型的数字

也就是数据类型不是给指针变量使用,而是给指针变量指向的内存使用的

切记:

指针变量分配的内存空间跟计算机硬件有关

32位系统,一个地址值为32位,4字节,所以对应的指针变量内存大小永远4字节

64位系统,一个地址值为64位,8字节,所以对应的指针变量内存大小永远8字节

所以指针变量没有数据类型一说

例如:

char *pa;  //定义一个字符类型的指针变量pa,pa对应的内存位4个字节,而pa指向的内存数据类型位char类型
		   // 将来它指向的内存只能保存一个char类型的数字,对应的内存也就1字节
short *pa;  //定义一个字符类型的指针变量pa,pa对应的内存位4个字节,而pa指向的内存数据类型位short类型
		   // 将来它指向的内存只能保存一个short类型的数字,对应的内存也就2字节

3. 连续定义多个指针变量形式:

int *pa, *pb;  // 定义两个指针变量
int *pa, *pb;  // pa是指针变量,pb是普通的变量,不是指针

4. 指针变量初始化方法

通过取地址运算符&进行;

例如:

int a = 250;  // 分配4字节内存,存储250数字,而这个数字类型位int类型
int *pa = &a;  // 定义一个指针变量分配4字节内存空间,然后保存变量a的首地址
				// 简称pa指向a
				
				
char b = 'A'; //分配1字节空姐,存储字符A的ASCII码
int *pb = &b;  // 定义指针变量分配4字节内存空间,然后保存变量b的首地址,简称pb指向b

注意:指针变量pa和pb指定的数据类型int,char不是给他们用,而是给a和b用的!

此时此刻脑子立马浮现内存操作示意图

在这里插入图片描述

问:一旦通过指针变量获取带指定的内存首地址,如何通过指针变量来对指向的内存为所欲为呢(读取值或者修改值)?

答:通过引用运算符*

5. 解应用运算符*

功能:通过指针变量对指向的内存区域进行各种访问操作

语法格式:*指针变量名

例如:

int a = 250;
int *pa = &a;
printf("pa保存变量a的首地址是%p\n", pa);
// 通过pa来获取指向的内存存储的数字250
printf("%d\n", *pa);
printf("pa占的字节%d\n", sizeof(pa));
// 通过pa对指向的内存进行修改
*pa = 520;   // 将指向的内存或者变量a的值修改为520
printf("pa保存变量a的首地址是%p\n", pa);

切记切记切记:

sizeof(指针变量名)永远等于4字节

参考代码:pointer.c

/*指针演示*/

#include <stdio.h>

int main(void) {
    // 定义初始化字符常量,分配1字节的内存
    char a = 'A';
    // 定义初始化指针变量pa,pa指向a
    char *pa = &a;

    // 打印变量a,指针变量pa和指针变量本身的地址
    printf("&a = %p, pa = %p, &pa = %p\n", &a, pa, &pa);
    // 打印指针变量a和指针变量本身占用内存的代销
    printf("sizeof(a) = %d, sizeof(pa) = %d\n", sizeof(a), sizeof(pa));

    // 通过pa获取a的值
    printf("%hhd, %c\n", *pa, *pa);
    printf("%hhd, %c\n", a, a);
    // 通过pa修改a的值
    *pa = 'B';
    printf("%hhd, %c\n", *pa, *pa);
    printf("%hhd, %c\n", a, a);

    return 0;
}

结果:

&a = 0xbf8a2de7, pa = 0xbf8a2de7, &pa = 0xbf8a2de8
sizeof(a) = 1, sizeof(pa) = 4
65, A
65, A
66, B
66, B

6. 特殊指针:空指针和野指针

6.1 空指针

空指针变量保存一个空地址,用NULL表示,其实就是编号为0的地址

空指针不可随意访问,否则直接造成程序崩溃!

例如:

int *pa = NULL;  // pa指向NULL
printf("pa指向的0地址保存的数据是%#x\n", *pa);  // 程序直接崩溃
*pa = 250;  // 修改0地址数据,程序直接崩溃

注意:全局指针变量没有初始化同样gcc也赋值一个NULL空地址

例如:

int *g_a;  // g_a = NULL = 0

6.2 野指针

就是没有初始化的指针变量(局部指针变量),它保存着一个随机地址,胡乱·指向一块没有分配的内存

如果访问野指针,也是非法访问,也会造成程序的崩溃!

例如:

int *pa;  //pa就是野指针
*pa = 250;  //操作野指针,程序直接崩溃

参考代码:pointer.c

/*空指针*/
int *pb = NULL;
printf("空指针指向的0地址保存的数据是%#x\n", *pb); //崩溃
*pb = 250;  //崩溃

结果:
段错误 (核心已转储)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值