C基础(五)作用域和内存管理

一、作用域

一个C语言变量的作用域可以是代码块作用域、函数作用域、或者文件作用域;代码块是{}直接的一段代码,出现{}之外的变量就是全局变量, 同一个作用域不能出现重名的变量,但是不同作用域是可以的。

#include<stdio.h>

int a = 2;//文件作用域

int main()
{
	int a = 0;//函数作用域
	{
		int a = 1;//代码块作用域
	}

	printf("%d\n",a); //优先访问当前作用域的变量,也就是a=0

	return 0;
}

当函数作用域的变量名和文件作用域的变量名一样时,函数作用域的变量优先被当前函数访问。

1.1 作用域和生命周期

类型作用域生命周期
auto变量一对{}内当前函数内
static局部变量一对{}内整个程序运行期间
extern变量整个程序内整个程序运行期间
static全局变量当前文件内整个程序运行期间
extern函数整个程序内整个程序运行期间
static函数当前文件内整个程序运行期间
register变量一对{}内当前函数内

auto自动变量
一般情况下代码块内部定义的变量都是自动变量,当然也可以显示的使用auto关键字。auto变量是自动在内存中出现和消失的,不需要我们管理内存。 文件作用域的变量就不是auto变量了,静态变量也不是auto变量。

register寄存器变量
通常变量在内存当中,如果能把变量放到CPU的寄存器里面,代码的执行效率会更高,例如:register int I;

静态变量
静态变量分为局部静态变量和全局静态变量,静态变量的内存位置在程序执行期间一直不改变的变量。C语言的静态变量是可以定义在代码块和函数内的,这点和java是不同的,java的static只能出现在类的成员位置上。静态变量在程序刚加载到内存的时候就出现了,所以和定义静态变量所在的{}无关,一直到程序结束的时候才会从内存中消失,同时静态变量只会初始化一次。

局部静态变量只能被这个代码块内部访问,而全局静态变量只能被当前文件任意位置访问。

局部静态变量
局部静态变量是指定义在代码块的作用域内的静态变量。

#include<stdio.h>

void test()
{
	static int a = 0; //静态变量只会初始化一次,和{}无关 ,它只能被test函数使用,其他函数无法使用.
	a++;
	printf("a=%d\n",a);
}

int main()
{
	int i;
	for(i = 0;i<10;i++)
	{
		test(); //调用上面的test方法
	}
 
	//printf("main call a=%d\n",a);无法访问代码块内的静态变量,编译直接报错

	return 0;
}

结果如下:

a=1
a=2
a=3
a=4
a=5
a=6
a=7
a=8
a=9
a=10

可以看到a的值是会一直累加的且初始化一次后不会重新初始化,它的生命周期是随程序的。

全局静态变量
代码块作用域外的静态变量叫静态全局变量,它在程序执行期间一直存在,但只能被定义这个变量的文件访问,其他文件无法使用extern关键字访问。

#include<stdio.h>

static int a = 0;

void test()
{
	a++;
}

int main()
{
	test();

	printf("a=%d\n",a);// a=1 

	//静态全局变量可以被当前文件任意位置访问,和全局变量一样,但是全局变量还可以被其他文件访问,作用范围最大
	a++; 

	printf("a=%d\n",a);// a=2
	
	return 0;

}

全局变量
在文件作用域定义的变量叫做全局变量(文件变量), 全局变量的存储方式和静态变量相同,但可以被多个文件通过extern关键字访问。

外部变量与extern关键字
外部变量是指定义在非当前文件中的全局变量,也就是说定义在其他的C文件中的变量(也叫全局变量), 如果要使用其他C文件中定义的全局变量,则需要在当前文件中使用extern关键字声明一下。

extern int i  //声明一个外部变量

同时使用gcc编译的时候,需要将外部变量所在的c文件一起编译,例如:

gcc -o a men2.c  mem3.c

同样的,如果要使用其他c文件定义的函数,也可以使用extern关键字在当前文件中显示声明一下。

全局函数和静态函数
在C语言中函数默认都是全局的,在所有的C文件中都可以通过extern关键字访问,而静态函数是使用关键字static可定义的函数,和静态全局变量一样只能被它定义的文件访问,其他文件都无法访问。

二、内存区域划分

C语言在内存中一共分为如下几个区域,分别是:

  1. 代码区:代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,这块内存是不可以在运行期间修改的,它是只读的。
  2. 常量区(全局区):存放常量(程序在运行的期间不能够被改变的量,例如: 10,字符串常量”abcde”, 数组的名字等)。
  3. 静态区(全局区):所有的全局变量/常量、静态变量/常量都存储到这个静态区,程序运行期间一直有效。
  4. 栈区(stack):每个线程都有自己专属的栈(stack),栈是一种先进后出的内存结构,所有的自动变量、函数的形参、函数的返回值,都是由编译器自动放入栈中,当一个自动变量超出其作用域时,自动从栈中弹出。对于自动变量什么时候入栈是不需要程序控制的,由C语言编译器实现;栈不会很大,一般都是以K位单位,当栈空间满了但是还往栈内存中压变量,就会出现栈溢出错误。
    C语言函数的参数入栈顺序是从由到左的, 而出栈就是从左到由的.
  5. 堆区(heap):一个进程就一个堆,它是被所有线程共享的,堆(heap)和栈一样也是一种在程序运行过程中可以随时修改的内存区域,但是没有栈那样先进后出的顺序, 堆是一个大容器,它的容量要远远大于栈,在C语言中堆内存的申请和释放需要手动通过代码来完成。

总结:
程序在运行之前分为: 代码区、data区、bss区

  • 代码区:存放CPU的指向指令,是所有程序共享的区域,是只读的.
  • data区:已初始化的全局变量和静态变量(全局和局部)的数据以及字符串常量.
  • bss区:未初始化的全局变量和静态变量(全局和局部)

其中data区和bss区统称全局区/静态区。

注意:编译时期分配的内存并不是真正的物理内存,而是地址的分配,只有在程序加载到内存中才会分配真是的内存。

程序运行之后分为:除了运行前的代码区、data区、bss区之外,程序运行后会多了栈区和堆区。

  • 栈区:由编译器自动分配和释放变量的内存,用于存放函数的参数,返回值,局部变量。
  • 堆区:堆的内存位于bss区和栈区之间,由程序员分配和释放,或者程序结束时由操作系统回收。

三、堆内存的分配和释放

操作系统在管理内存时,最小单位是内存页,而不是字节,什么意思呢?
意思就是说假如你在程序中申请了1k(1024字节)的内存大小,操作系统可能会返回4k的大小,这种做的好处是效率提高了,避免频繁的分配内存,但是缺点就是浪费了一些内存。

3.1 malloc分配堆内存

void * malloc(size_t _Size);

这个函数在堆中分配参数_Size指定大小的内存,单位是字节,函数返回值void*指针,表示任意类型的指针。使用时需要导入stdlib.h头文件。

3.2 free释放堆内存

void free(void *p);

free负责释放malloc分配的堆内存,参数p为malloc返回的堆内存地址,通常和malloc配套使用。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	//定义一个栈变量指向堆内存地址,堆内存大小10个字节
	char *s = malloc(10);
	
	//拷贝abcd字符串到s变量分配的内存中
	strcpy(s,"abcd");

	printf("%s\n",s);
	
	//释放堆内存中的内存,注意并不是把s变量释放了,而是释放了s指向的那块堆内存,
	//s变量是在栈内的,他是自动变量,不需要我们维护.
	free(s);

	//int a[1000000000000];//在栈中定义一个数组,由于栈内存空间有限,不适合定义大数据,会栈溢出

	//大数据适合在堆内存中创建
	int *p = malloc(10000000000000*sizeof(int));
	free(p);

	return 0;
}

3.3 思考:解决函数返回值是指针的问题

当函数的返回值是指针类型时, 如果函数内返回的地址是一个自变量的地址,那么编译是会报警告的,这个问题是因为函数内定义的自变量出了作用域就会消失,因为它存在栈内存中,由系统自动管理。
如下代码就是一个错误的示范

#include<stdio.h>

int *test1()
{	
	int a = 10; //函数内定义的变量,出了作用域就会消失,因为它存在栈内存中,由系统自动管理
	return &a;
}

int main()
{
	int *p = test1(); //编译时会警告,因为p指向的内存是在栈中分配给a变量的,test1函数执行完就释放了a,a不存在了.
	printf("%d\n",*p);

	return 0;
}

编译器会自动检测并报错提示
在这里插入图片描述

解决方案有2种:

方案一: 返回一个在堆内存分配的地址指针变量

在函数内使用malloc分配堆内存给栈的指针变量,这样当栈变量离开函数作用域被回收后,但是分配的堆内存空间还是有效的,里面存放的值也是可以访问的,在调用这个函数的时候拿到堆的内存地址就可以操作这块区域的数据,但是操作完后记得调用free来释放堆内存。

#include <stdio.h>
#include <stdlib.h>

int *test2()
{
    // 任何变量类型包括数组如果要在函数外使用,都必须使用堆内存分配
    int *p = malloc(1 * sizeof(int));
    *p = 10;
    return p;
}

int main()
{
    // 这样p变量指向的内存是在堆中分配的. 所以不会被自动回收.
    int *p = test2(); 
    printf("%d\n", *p); // 10

    // 记得释放
    free(p);
    return 0;
}

方案二: 在函数调用处定义自变量

不要在函数内创建变量,而是在调用处创建变量,然后传递地址到目标函数处理,处理完成返回的地址其实和创建时指向的是一样的,都是在栈内存中。由于变量定义是在函数调用处定义的,只要调用处的作用域没有结束,就可以继续访问。

#include<stdio.h>

int * test(int *a)
{
	*a = 10;
	return a;
}

int main()
{
	int a; //在调用处定义变量
	int * p = test(&a);  //调用上面的方法,返回指针变量p , 此时指针变量p所指向的地址是存在栈内存中的. 因此不需要手动释放内存
	printf("%d,%d\n",a,*p);

	return 0;
}

注意:free函数释放的字节数是根据malloc申请的大小来释放的, 也就是说从指针变量当前位置往后多少个字节就释放多少, 因此特别需要注意指针变量++操作后, 会影响free的结果, 程序运行会异常, 因此free前需要做相应的–操作。
在这里插入图片描述

3.4 思考:局部静态变量和常量所指向的地址的值出了作用域还能访问吗?

可以,因为静态变量和常量都是在程序运行期间有效的,且不需要手动释放内存。

#include <stdio.h>

char *test()
{
    static char a[100] = "hello"; //静态变量的地址是运行期有效的
    char *p = a;                  //定义一个指针变量指向a的地址
    p++;                          // 指针++后指向的就是e的位置了
    return p;
}

const char *test1()
{
    // 定义了一个字符串常量, 由于常量是只读的,所以返回值类型最好加上const
    const char *s = "hello1";
    return s;
}

const char *test2()
{
    return "hello2"; //直接返回字符串常量, 效果和test1函数一样.
}

int main()
{
    char *str = test();
    printf("%s\n", str); //可以正确输出ello ,因为str指向的地址是静态变量的地址,不会受函数作用域影响

    const char *str1 = test1();
    const char *str2 = test2();
    printf("str1=%s,str2=%s\n", str1, str2); //可以正确输出hello1和hello2,因为常量的地址也是不会变的

    //printf("%s\n",s); 虽然地址不会变,但是s还是栈的变量,只是指向了常量的地址而已. 所以出了函数体后,s变量就访问不了了.

    return 0;
}

3.5 案例:使用堆内存解决strcat追加字符串无法提前预知内存大小的申请问题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char a[] = "hello";
    char b[] = "hhhhhhhhhhhhhhhhhhhhhhhh";

    //动态分配内存, 根据a和b的字符串长度动态申请堆内存大小
    char *p = malloc(strlen(a) + strlen(b) + 1);
    //拷贝
    strcpy(p, a);
    //追加
    strcat(p, b);

    printf("p=%s\n", p); // p=hellohhhhhhhhhhhhhhhhhhhhhhhh

    return 0;
}

3.6 calloc分配指定大小的堆内存

void * calloc(size_t _Count, size_t _Size);

与malloc类似,负责在堆中分配内存,参数1是所需内存单元数量,参数2是每个内存单元的大小(单位:字节),calloc自动将分配的内存值0,因此不需要使用memset来清空。 而malloc分配的内存则需要使用memset来清空。

int *p = (int *)calloc(100, sizeof(int));//分配100个int
//等效于
int *p  = (int*)malloc(100 * sizeof(int))

3.7 realloc重新分配新的堆内存

重新分配用malloc或者calloc函数在堆内存中分配的空间大小。

void * realloc(void *p, size_t _NewSize);

参数1:p为之前用malloc或者calloc分配的内存地址,等于NULL,那么realloc等效于malloc
参数2:_NewSize为重新分配后的最终内存的大小(单位:字节).
返回值:
成功返回新分配的内存首地址, 失败则返回NULL , realloc内部会重新分配一个连续的内存空间, 如果源地址后面不够分配, 他就会新申请一块空间, 而且这中间会自动的完成拷贝旧区域的数据到新区域, 完成后会自动的把旧区域内存释放, 这个过程是不用我们关心, 我们只需要关注的是它返回的新地址, 需要我们手动释放的也是这个返回的新地址对应的内存空间.

使用场景:如果一个变量初始分配了10个字节的堆大小, 后面发现不够用来了,需要20个字节, 那么就可以使用realloc来增加到20个字节大小,例如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char *s1 = calloc(10, sizeof(char));
    char *s2 = calloc(6, sizeof(char));

    strcpy(s1, "123456789");
    strcpy(s2, "adcde");

    //此时s1的申请的空间已经用完了, 如果还想把s2也追加到s1中,则需要对s1进行扩容
    s1 = realloc(s1, strlen(s1) + strlen(s2) + 1);

    //追加s2
    strcat(s1, s2);

    printf("s1=%s\n", s1); // s1=123456789adcde

    free(s1);
    free(s2);

    return 0;
}

3.8 正确处理函数内分配堆内存的问题

注意:如果想给一个指针通过函数调用来分配堆内存,那么必须要将该指针的地址作为形参传入, 该函数的形参类型一定是二级指针. 否则无法实现这种需求。

先来看一段代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void test(char *s)
{
    strcpy(s, "hello");
}

int main()
{
    char *p = calloc(10, 1); //在堆中分配10个字节的内存大小
    test(p);                 //给p变量赋值

    printf("%s\n", p); // hello

    free(p); //释放内存

    return 0;
}

接着将上面的代码修改下为下面这种后,你会发现输出结果还是null。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void test(char *s)
{
    s = calloc(10, 1); //在这里申请堆内存
    strcpy(s, "hello");
}

int main()
{
    char *p = NULL;
    test(p); //调用test函数,把p实参传递给函数的形参s

    printf("p=%s\n", p); //p还是NULL, 因为test函数执行完成后,s变量就消失了

    free(p); //释放内存,直接报错,因为p变量执行的内存是在栈中

    return 0;
}

前面代码之所以可以是因为,变量p是在调用处分配了内存,然后调用test函数给形参s赋值,此时s栈变量指向的堆地址还是在main函数申请的, 所以离开了test函数后, main操作的变量p并不影响,并且指向的堆内存地址对应的值也是可以正常查看修改后的值的。

那么如何解决在调用处没有申请堆内存却能正常使用的问题呢?
将p变量的地址传递给test函数, 函数参数改为二级指针, 然后函数体内操作一级指针的值即可。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void test(char **s)
{
    //给1级指针分配堆内存地址
    *s = calloc(10, 1);
    //赋值
    strcpy(*s, "hello");
}

int main()
{
    char *p = NULL;
    test(&p); //传入一级指针的地址

    printf("%s\n", p); // hello

    //释放
    free(p);

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 愉快的开始-HELLO WORLD 14 1.1 INCLUDE头文件包含 14 1.2 MAIN函数 14 1.3 注释 14 1.4 {}括号,程序题和代码块 14 1.5 声明 14 1.6 C语言自定义名字的要求 15 1.7 PRINTF函数 15 1.8 RETURN语句 15 1.9 SYSTEM系统调用 15 1.9.1 System返回值在windows和unix下的不同, 15 1.9.2 POSIX 15 1.10 C语言编译过程,GCC参数简介 16 1.10.1 C语言编译过程 16 1.10.2 -E预编译 16 1.10.3 -S汇编 16 1.10.4 -c编译 16 1.10.5 链接 16 1.11 操作系统结构 17 1.11.1 用户模式 17 1.11.2 内核模式 17 1.12 64位,32位系统区别 18 1.12.1 CPU内部结构与寄存器 18 1.12.2 RISC与CISC CPU构架 18 1.12.3 SPARC,x86与ARM 18 1.13 汇编语言 18 1.13.1 I386汇编简介 18 1.13.2 VS反汇编 19 1.14 IDE工具 19 1.14.1 QT常用快捷键 19 1.14.2 VS常用快捷键 19 1.14.3 VS断点,调试 19 2 C语言中的数据类型 19 2.1 常量 19 2.1.1 #define 19 2.1.2 const 19 2.2 字符串常量 20 2.3 二进制数、位、字节与字 20 2.4 八进制 20 2.5 十六进制 20 2.6 原码 21 2.7 反码 21 2.8 补码 21 2.9 SIZEOF关键字 22 2.10 INT类型 22 2.10.1 int常量,变量 22 2.10.2 printf输出int值 23 2.10.3 printf输出八进制和十六进制 23 2.10.4 short,long,long long,unsigned int 23 2.10.5 整数溢出 23 2.10.6 大端对齐与小端对齐 23 2.11 CHAR类型 24 2.11.1 char常量,变量 24 2.11.2 printf输出char 24 2.11.3 不可打印char转义符 24 2.11.4 char和unsigned char 25 2.12 浮点FLOAT,DOUBLE,LONG DOUBLE类型 25 2.12.1 浮点常量,变量 25 2.12.2 printf输出浮点数 25 2.13 类型限定 25 2.13.1 const 25 2.13.2 volatile 26 2.13.3 register 26 3 字符串格式化输出和输入 26 3.1 字符串在计算机内部的存储方式 26 3.2 PRINTF函数,PUTCHAR函数 27 3.3 SCANF函数与GETCHAR函数 28 4 运算符表达式和语句 29 4.1 基本运算符 29 4.1.1 = 29 4.1.2 + 29 4.1.3 – 29 4.1.4 * 29 4.1.5 / 29 4.1.6 % 29 4.1.7 += 29 4.1.8 -= 29 4.1.9 *= 29 4.1.10 /= 30 4.1.11 %= 30 4.1.12 ++ 30 4.1.13 -- 30 4.1.14 逗号运算符 30 4.1.15 运算符优先级 30 4.2 复合语句 31 4.3 空语句 31 4.4 类型转化 31 5 条件分支语句 31 5.1 关系运算符 31 5.1.1 < 31 5.1.2 <= 31 5.1.3 > 32 5.1.4 >= 32 5.1.5 == 32 5.1.6 != 32 5.2 关系运算符优先级 32 5.3 逻辑运算符 32 5.3.1 && 32 5.3.2 || 32 5.3.3 ! 33 5.4 IF 33 5.5 IF ELSE 34 5.6 IF ELSE IF 34 5.7 SWITCH与BREAK,DEFAULT 35 5.8 条件运算符? 36 5.9 GOTO语句与标号 36 6 循环语句 36 6.1 WHILE 36 6.2 CONTINUE 37 6.3 BREAK 37 6.4 DO WHILE 37 6.5 FOR 37 6.6 循环嵌套 37 7 数组 38 7.1 一维数组定义与使用 38 7.2 数组在内存的存储方式 38 7.3 一维数组初始化 38 7.4 二维数组定义与使用 39 7.5 二维数组初始化 39 8 字符串与字符数组 39 8.1 字符数组定义 39 8.2 字符数组初始化 39 8.3 字符数组使用 40 8.4 随机数产生函数RAND与SRAND 40 8.5 用SCANF输入字符串 40 8.6 字符串的结束标志 41 8.7 字符串处理函数 41 8.7.1 gets 41 8.7.2 fgets函数 41 8.7.3 puts函数 42 8.7.4 fputs函数 42 8.7.5 strlen,字符串长度 42 8.7.6 strcat,字符串追加 42 8.7.7 strncat,字符串有限追加 43 8.7.8 strcmp,字符串比较 43 8.7.9 strncmp,字符串有限比较 43 8.7.10 strcpy字符串拷贝 43 8.7.11 strncpy字符串有限拷贝 43 8.7.12 sprintf,格式化字符串 43 8.7.13 Sscanf函数 44 8.7.14 strchr查找字符 44 8.7.15 strstr查找子串 44 8.7.16 strtok分割字符串 44 8.7.17 atoi转化为int 45 8.7.18 atof转化为float 45 8.7.19 atol转化为long 45 9 函数 45 9.1 函数的原型和调用 45 9.2 函数的形参与实参 45 9.3 函数的返回类型与返回值 46 9.4 MAIN函数与EXIT函数与函数的RETURN语句 46 9.5 多个源代码文件程序的编译 47 9.5.1 头文件的使用 47 9.5.2 #include与#define的意义 47 9.5.3 #ifndef与#endif 47 9.6 函数的递归 48 9.6.1 递归的过程分析 48 9.6.2 递归的优点 52 9.6.3 递归的缺点 52 1 指针 52 1.1 指针 52 1.1.1 指针的概念 52 1.1.2 指针变量的定义 52 1.1.3 &取地址运算符 52 1.1.4 无类型指针 52 1.1.5 NULL 53 1.1.6 空指针与野指针 53 1.1.7 指针的兼容性 53 1.1.8 指向常量的指针与指针常量 54 1.1.9 指针与数组的关系 54 1.1.10 指针运算 54 1.1.11 通过指针使用数组元素 55 1.1.12 指针数组 55 1.1.13 指向指针的指针(二级指针) 55 1.1.14 指向二维数组的指针 57 1.1.15 指针变量做为函数的参数 57 1.1.16 一维数组名作为函数参数 57 1.1.17 二维数组名作为函数参数 58 1.1.18 const关键字保护数组内容 58 1.1.19 指针做为函数的返回值 58 1.1.20 指向函数的指针 59 1.1.21 把指向函数的指针做为函数的参数 60 1.1.22 memset,memcpy,memmove函数 61 1.1.23 指针小结 63 2 字符指针与字符串 64 2.1 指针和字符串 64 2.2 通过指针访问字符串数组 64 2.3 函数的参数为CHAR * 64 2.4 指针数组做为MAIN函数的形参 65 3 内存管理 65 3.1 作用域 65 3.1.1 auto自动变量 65 3.1.2 register寄存器变量 65 3.1.3 代码块作用域的静态变量 66 3.1.4 代码块作用域外的静态变量 66 3.1.5 全局变量 66 3.1.6 外部变量与extern关键字 66 3.1.7 全局函数和静态函数 66 3.2 内存四区 66 3.2.1 代码区 67 3.2.2 静态区 67 3.2.3 栈区 67 3.2.4 栈溢出 68 3.2.5 堆区 68 3.3 堆的分配和释放 70 3.3.1 malloc 70 3.3.2 free 70 3.3.3 calloc: 70 3.3.4 realloc 71 4 结构体,联合体,枚举与TYPEDEF 71 4.1 结构体 71 4.1.1 定义结构体struct和初始化 71 4.1.2 访问结构体成员 71 4.1.3 结构体的内存对齐模式 72 4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针 73 4.1.9 指向结构体数组的指针 73 4.1.10 结构中的数组成员和指针成员 73 4.1.11 在堆中创建的结构体 74 4.1.12 将结构作为函数参数 74 4.1.13 结构,还是指向结构的指针 74 4.2 联合体 75 4.3 枚举类型 75 4.3.1 枚举定义 75 4.3.2 默认值 76 4.4 TYPEDEF 76 4.5 通过TYPEDEF定义函数指针 76 5 文件操作 77 5.1 FOPEN 77 5.2 二进制和文本模式的区别 77 5.3 FCLOSE 78 5.4 GETC和PUTC函数 78 5.5 EOF与FEOF函数文件结尾 78 5.6 FPRINTF,FSCANF,FGETS,FPUTS函数 78 5.7 STAT函数 78 5.8 FREAD和FWRITE函数 79 5.9 FREAD与FEOF 79 5.10 通过FWRITE将结构保存到二进制文件中 79 5.11 FSEEK函数 80 5.12 FTELL函数 80 5.13 FFLUSH函数 80 5.14 REMOVE函数 81 5.15 RENAME函数 81 6 基础数据结构与算法 82 6.1 什么是数据结构 82 6.2 什么是算法 82 6.3 排序 83 6.3.1 冒泡排序 83 6.3.2 选择排序 83 6.4 查找 83 6.4.1 顺序查找 83 6.4.2 二分查找 83 6.5 链表 84 6.5.1 单向链表定义 84 6.5.2 单向链表数据结构定义 85 6.5.3 单向链表的实现 85
大学计算机应用基础 一、选择题: 1.计算机内部的一切信息均采用( )表示。 A.十进制 B.二进制 C.十六进制 D.八进制 2.反映计算机存储容量的基本单位是( ) A.二进制位 B.字节 C.字 D.双字 3.世界上首次提出存储程序计算机体系结构的是( ) A.贝尔 B.阿兰 图灵 C.冯 诺伊曼 D.乔治 布尔 4.关闭一个活动窗口,可按组合键( ) A.<Alt> + <F4> B.<Ctrl> + <F4> C.<Alt> + <Esc> D.<Ctrl> + <Esc> 5.用电子计算机实现炼钢炉的自动调温,是计算机在( )领域中的应用。 A.计算机辅助系统 B.过程控制 C.科学计算 D.数据处理 6.当一个文档存盘后被关闭,该文档将( ) A.保存在外存中 B.保存在内存中 C.保存在剪贴板中 D.丢失了 7.在下面的叙述中,( )说法是错误的。 A.键盘和显示器属于计算机的I/O设备 B.微型计算机的核心部件是CPU C.微机在使用中突然停电,ROM中的信息不受影响, RAM中信息全部丢失 D.软盘驱动器属于主机,软盘属于外设 8.在计算机系统中,CPU可以直接读/写( )中的内容。 A.软盘 B.光盘 C.硬盘 D.内存 9.要通过控制面板来设置桌面壁纸,应该选择( ) A. B. C. D. 10.操作系统的功能是( )。 A.处理器管理、存储器管理、设备管理、文件管理 B.运算器管理、控制器管理、打印机管理、磁盘管理 C.硬盘管理、软盘管理、存储器管理、文件管理 D.程序管理、文件管理、编译管理、设备管理 答案:1.B 2.B 3.C 4.A 5.B 6.A 7.D 8.D 9.B 10.A 二、填空题: 1.第四代计算机主要采用的电子器件是 。 2.一个完整的微型计算机硬件系统应由 、控制器、 、输入设备和输出设备组成。 3.对计算机软件和硬件资源进行管理和控制的软件是 。 4.在Windows中,用于中英文输入法切换的快捷键是 。 5.将十进制数128转换成二进制数是________________,转换成八进制数是__________ _,转换成十六进制数是______________。 6.在Word中,只有在______________视图下可以显示水平标尺和垂直标尺。 7.在Excel中可以使用____________函数对一些单元格内的数字求和。 8.在Excel单元格中输入"=4*3+5^3/2",则按Enter键后此单元格显示为___________。 9.Internet采用的标准网络协议是______________协议。 10.最常见的计算机网络拓扑结构有:_________________、__________________ 和_________________三种。 答案: 1.超大规模集成电路 2.运算器、存储器 3.操作系统 4.Ctrl+空格 5.1111111、177、7F 6.页面 7.SUM() 8.74.5 9.TCP/IP 10.总线型、星型、环型 三、简答题: 1、冯.诺依曼体系结构提出了计算机设计的三个基本思想是什么? 2、计算机网络的分类有哪些? 3、运用混合引用方法,在EXCEL中创建一个九九乘法表,请写出操作步骤。 4、简要回答计算机的应用和计算机的基本工作原理。 5、简要回答计算机操作系统的概念和主要作用。 6、简要回答在Word文档另存的操作步骤。 7、简要回答在Word文档中插入表格的操作步骤。 8、简要回答在Excel表格中数据排序的操作步骤。 答案: 1. 冯.诺依曼体系结构提出了计算机设计的三个基本思想是什么? 答:(1)计算机由运算器、控制器、存储器、输入设备和输出设备个基本部分组成。 (2)采用二进制形式表示计算机的指令和数据。 (3)将程序和数据存放在存储器中,计算机依次自动地执行程序。 2. 计算机网络的分类有哪些? 答:按网络的传输技术划分为广播式网络与点到点网络; 按网络的使用者划分为公用网络与私有网络; 按通信介质划分为有线网络与无线网络; 按网络的地理范围划分为局域网、城域网和广域网。 3. 运用混合引用方法,在EXCEL中创建一个九九乘法表,请写出操作步骤。 答:(1)准备将单元格B2的公式复制到其他的单元格中。 (2)希望第一个乘数的最左列不动($A)而行跟着变动,希望第二个乘数的最上行不动 ($1)而列跟着变动,因此B2的公式应该改为"=$A2*B$1"。 (3)选定包含混合引用的单元格B2。 (4)单击"开始"选项卡的"剪贴板"组中的"复制"按钮。 (5)选定目标区域B2:I9,单击"开始"选项卡的"剪贴板"组中的 "粘贴"按钮。 4、 答:计算机应用有:(1)科学计算(2)信息处理(3)过程控制(4)计算机

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值