字符串指针和字符数组,静态全局、静态局部、全局和局部变量区别,字符串常量和字符串变量,程序的内存分配
- 格式:docx
- 大小:25.36 KB
- 文档页数:4
C/C++语言变量声明内存分配2010-11-08 07:10:20| 分类:编程|字号订阅一个由c/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)—程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
程序结束时由编译器自动释放。
2、堆区(heap)—在内存开辟另一块存储区域。
一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—编译器编译时即分配内存。
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
- 程序结束后由系统释放4、文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放5、程序代码区—存放函数体的二进制代码。
例子程序这是一个前辈写的,非常详细//main.cppint a = 0; 全局初始化区char *p1; 全局未初始化区main(){int b;// 栈char s[] = "abc"; //栈char *p2; //栈char *p3 = "123456"; //"123456/0"在常量区,p3在栈上。
static int c =0;//全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20);//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456/0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}===============C语言程序的内存分配方式1.内存分配方式内存分配方式有三种:[1]从静态存储区域分配。
C字符串常量和字符串变量定义和区别字符串常量定义:在⼀个双引号""内的字符序列或者转义字符序列称为字符串常量例如:"HA HA!" "abc" "\n\t"这些字符串常量是不能改变的,如果试图改变指针所指向的内容是错误的因为字符串常量是存在静态内存区的,不可以改变的。
如定义字符串常量:char* a="i love you.";*a='h'; //试图改变它这是错误的。
系统显⽰:string.exe 中的 0x00d71398 处未处理的异常: 0xC0000005: 写⼊位置 0x00d7573c 时发⽣访问冲突或者报该内存不能为written。
字符串变量在C语⾔中没有纯粹的c语⾔字符串变量,可以通过⼀个字符数组来体现,这样就可以对字符数组中的内容进⾏改变!如上式可改为。
如定义字符串变量:char a[]="i love you.";*a='h';/***字符串常量*程序将会报错,不能改变字符串常量值。
*修改失败**/#include <stdio.h>#include <stdlib.h>void main(){char *str = "abcdef";printf("%s,%p\n", str,str);*str = 'C'; //修改第三个字符为⼤写printf("%s,%p\n", str);}/***字符串变量*程序将改变字符串变量中其中的值。
*修改成功**/#include <stdio.h>#include <stdlib.h>void main(){char str[] = "abcdef";char *p_str = str;printf("%s\n", p_str);*(p_str+2) = 'C'; //修改第三个字符为⼤写printf("%s\n", p_str);}⼩结:字符串常量:不能对值修改。
C语⾔--字符串详解 字符串是⼀种⾮常重要的数据类型,但是C语⾔不存在显式的字符串类型,C语⾔中的字符串都以字符串常量的形式出现或存储在字符数组中。
同时,C 语⾔提供了⼀系列库函数来对操作字符串,这些库函数都包含在头⽂件 string.h 中。
⼀、字符串常量和字符数组1.1、什么是字符串常量 C 语⾔虽然没有字符串类型,但是 C语⾔提是存在字符串这个概念的,也就是字符串常量:以 NUL 字节结尾的 0 个或多个字符组成的序列。
字符串常量是不可被修改的,⼀般⽤⼀对双引号(" ")括起的⼀串字符来表⽰字符串常量,如: "Hello!"、"\aWarning!\a"、"123abc\n"、"" 字符串常量可以为空,如""就是⼀个空的字符串常量,但是即使为空,还是存在⼀个终⽌符 NUL 的。
(在 C 语⾔中,常⽤转义字符 \0来表⽰ NUL)1.2、字符串常量与指针 字符串常量与指针关系密切,因为字符串常量的值,实际上表⽰的是存储这些字符的内存空间的地址,更准确地说是字符串常量中第 1个字符的地址,⽽不是这些字符本⾝。
因此,在 C 语⾔中是不能直接进⾏字符串赋值的(因为没有字符串类型嘛)。
在 C 语⾔中,常通过声明⼀个指向 char 类型的指针并将其初始化为⼀个字符串常量的⽅式来访问⼀个字符串:char *message = "Hello World!";// 上⾯的语句也可以拆分成下⾯两句char *message;message = "Hello World!"; // 这句话看起来像是字符串复制,其实不是,只是涉及到指针操作 上述语句声明了⼀个指向 char 类型的指针,并⽤字符串常量中第 1 个字符的地址对该指针进⾏初始化。
可以通过字符指针 message 来访问字符串常量:#include <stdio.h>int main(){ char *message = "Hello World!"; printf("%s\n",message); while(*message != '\0'){ printf("%c ",*message++); } printf("\n"); return0;}/* output:* Hello World!* H e l l o W o r l d !*/ 这段代码,使⽤字符指针遍历了字符串常量中的每⼀个字符。
c语言全局变量和局部变量区别
全局变量和局部变量的区别有:1.有效范围不一样,2.内存空间不同,3.使用区间不同。
局部变量只在本函数范围有效,在此函数以外是不能使用这些变量;全局变量的有效范围是从定义变量的位置开始到本源文件结束。
局部变量是程序运行到该函数时给该变量分配内存空间,函数结束则释放该内存空间。
全局变量是程序运行时事先分配内存空间,当程序结束时释放内存。
全局变量:作用于整个程序文件;局部变量:作用于所属语句块或函数中。
全局变量的存有主要存有以下一些原因:采用全局变量可以挤占更多的内存(因为其生命期短),不过在计算机布局很高的今天,这个不必须算什么问题,除非采用的就是非常大对象的全局变量,能避免就一定必须防止。
采用全局变量程序运行时速度更慢一些(因为内存不须要再分配),同样也慢没法多少。
对于局部变量的名字空间污染,这个在不能采用太多变量时就是可以防止的。
当全局变量与局部变量下文的时候,起至促进作用的就是局部变量,全局变量被屏蔽掉。
还可以用extern在函数外对全局变量声明,并使全局变量的作用域从声明处至文件的完结。
全局变量的优先度高于局部变量。
总之,全局变量可以采用,但是全局变量采用时应特别注意的就是尽可能并使其名字不易认知,而且无法太短,防止名字空间的污染;防止采用非常大对象的全局变量。
在c语言等面向过程语言中,局部变量可以和全局变量下文,但是局部变量可以屏蔽全局变量。
在函数内提及这个变量时,可以使用同名的局部变量,而不能使用全局变量。
C语⾔字符串替换:字符,字符串,字符数组详解⽬录案例描述案例分析必备知识1,字符数组(1)字符数组的定义(2)字符数组的初始化2,字符串概念(1)字符串的概念(2)⽤字符初始化字符数组(3)获取字符串的长度3,字符串与指针4,字符数组与字符指针总结案例描述字符串替换是处理字符串时最常见的操作之⼀,也是学习字符串必须掌握的知识。
本案例要求通过编程实现字符串“Good moring”到“Good evening”的转换。
案例分析我们需要从字符串中被替换的位置开始,将要替换的内容逐个复制到原字符串中,直到字符串结束或者替换的字符串结束为⽌。
为了顺利完成案例,需要先学习字符数组,字符串,字符指针等基础知识。
必备知识1,字符数组字符数组是存放字符数据的数组,其中每⼀个元素都是单个字符(1)字符数组的定义字符数组定义的语法格式如下:char 数组名[常量表达式];char 数组名[常量表达式1][常量表达式2]在上述语法中,分别列举了定义⼀维字符数组和⼆维字符数组的⽅法。
⽰例代码如下:char ch[6];(2)字符数组的初始化在数组定义的同时也可以对数组中的元素进⾏赋值,这个过程称为数组的初始化,⽰例代码如下:char c[5] = {'h','e','l','l','o'};注意字符数组的初始化很简单,但要注意以下⼏点。
(1)元素个数不能多于字符数组的⼤⼩,否则编译器会出错(2)如果初始项少于数组长度,则空余元素均会被赋值为空字符(‘\0')(3)如果没有指定数组⼤⼩,则编译器会根据初始项的个数为数组分配长度(4)也可以初始化⼆维数组(和整型数组基本⼀致)2,字符串概念(1)字符串的概念字符串是由数字、字母、下划线和空格等各种字符组成的⼀串字符,是个常量,字符串的末尾都默认有⼀个'\0'作为结束符。
"abcde"" "上⾯这两⾏都是字符串,只不过第⼆个字符串中的字符都是空格字符串在各种编程语⾔中都是⾮常重要的数据类型,但是C语⾔中没有字符串的固定类型,通常⽤字符数组的形式来存储和处理字符串,这种字符数组必须以'\0'结尾。
c语言的32个关键字及其含义C语言是一门广泛应用于计算机编程的高级编程语言,其简洁、高效的特点使之成为许多程序员的首选。
而C语言的关键字则是构成C语言语法结构的基石,掌握这些关键字的含义对于编写高质量的C代码至关重要。
本文将会介绍C语言的32个关键字及其含义。
一、自动变量(auto)auto关键字用于声明自动变量,自动变量是在代码块中定义的变量。
它们的生命周期仅限于所在代码块,函数的参数也属于自动变量。
二、断言(assert)assert关键字用于在程序运行时进行断言验证,如果断言条件为假,程序将会中止执行。
断言通常用于调试和排错。
三、带宽限定(band)band关键字用于限定带宽,常用于定义延迟函数、外部中断和总线访问等场景。
四、布尔类型(bool)bool关键字用于声明布尔类型的变量,布尔类型只有两个值:真和假。
一般用于判断语句和循环语句的条件。
五、跳过(break)break关键字用于跳出循环或者switch语句块,提前终止程序的执行。
六、函数调用(call)call关键字用于向函数传递参数并调用函数。
它与return关键字相对应,后者用于从函数返回结果。
七、case标签(case)case关键字用于定义switch语句中不同分支的标签,根据不同的条件执行相应的代码。
八、常量(const)const关键字用于声明常量,常量值在程序执行期间不可更改。
通常用于定义不变的特定值,提高代码的可读性和可维护性。
九、continue(continue)continue关键字用于结束当前循环的当前迭代,并进入下一轮循环的迭代。
通常用于跳过某些不满足条件的循环迭代。
十、默认(default)default关键字用于定义switch语句中默认分支的代码块。
如果没有匹配的case 标签,将会执行默认分支的代码。
十一、定义(define)define关键字用于定义宏。
宏是一种在程序编译之前被展开的符号常量或者代码片段。
c语⾔之创建字符串的两种⽅式在c语⾔中,⼀般有两种⽅式来创建字符串//第⼀种,利⽤字符指针char* p = "hello";//第⼆种:利⽤字符数组char str[] = "hello";那么,它们之间有什么区别呢?以例⼦说明:#include<stdio.h>#include<iostream>char* returnStr(){char* p = "hello world!";return p;}int main(){char* str = NULL;str = returnStr();printf("%s\n", str);system("pause");return0;}输出:以上代码是没有问题的,"hello world"是⼀个字符串常量,存储在常量区,p指针指向该常量的⾸字符的地址,当returnStr函数退出时,常量区中仍然存在该常量,因此仍然可以⽤指针访问到。
#include<stdio.h>#include<iostream>char* returnStr(){char p[] = "hello world!";return p;}int main(){char* str = NULL;str = returnStr();printf("%s\n", str);system("pause");return0;}输出:以上代码有问题,输出为乱码。
这⼀段代码和之前的最主要的区别就是returnStr中字符串的定义不同。
这⾥使⽤字符数组定义字符串。
因此这⾥的字符串并不是⼀个字符串常量,该字符串为局部变量,存查在栈中,当returnStr函数退出时,该字符串就被释放了,因此再利⽤指针进⾏访问时就会访问不到,输出⼀堆乱码。
一.C语言中,从变量的作用域角度来分,可以分为全局变量和局部变量。
二.变量值存在的时间角度来分,可以分为静态存储方式和动态存储方式。
所谓静态存储方式是指在程序运行期间有系统分配固定的存储空间的方式。
而动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式。
具体包含4种:自动的(auto),静态的(static),寄存器的(register),外部的(extern)。
1. 自动的(auto)在调用函数时系统会给他们分配存储空间,在函数调用结束时就自动释放这些存储空间,这类局部变量称为自动变量。
2. 静态的(static)为了满足局部变量的值在函数调用结束后不消失而且保留原值,既占用的存储单元不释放,就出现了静态的局部变量,用static来声明的局部变量。
局部变量的特点:(1)相对自动变量(即动态局部变量),在程序的运行期间都占用静态存储区,直到程序结束才释放该存储区。
(2)静态局部变量只是在程序编译时赋初值,以后每次调用时不再重新赋初值,而只是保留上次函数调用结束时的值。
动态局部变量编译时不赋初值,直到程序调用时才给变量赋值,每次调用都要赋初值。
(3)在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时会自动赋初值0或空字符。
而对动态局部变量,不赋初值则它的值是一个不确定的值,因为动态变量每次都要自动分配存储空间,存储空间的值是不固定的。
(4)静态局部变量在函数调用结束后不释放,但其他函数是不能调用的。
3.寄存器的(register)为了提高程序的执行效率,对一些运算频繁的变量定义为寄存器变量可以节省每次程序执行时的内存读取,大大节省了时间,提高了效率。
寄存器的一些特点:(1)寄存器变量的特点程序运行时分配寄存器存储空间,结束时释放。
这个特点限定了只能把局部自动变量和形式参数定义为寄存器变量。
(2)局部静态变量不能定义为寄存器变量。
4. 外部的(extern)外部变量是在函数的外部定义的全局变量,他的作用是从变量的定义初开始,到本程序文件的末尾。
局部变量和全局变量的区别1.定义的位置不同:
局部变量定义在⽅法内部。
成员变量定义在⽅法的外部,直接在类中。
2.作⽤范围不同:
局部变量只有在⽅法当中才能使⽤,出了⽅法就不能⽤了。
成员变量在整个类中全都可以使⽤。
3.默认值不同:
局部变量没有默认值,如果想要使⽤,必须要⼿动进⾏赋值。
成员变量如果没有赋值会有默认值,规则和数组⼀样。
4.⽣命周期不同:
局部变量随着⽅法进栈⽽诞⽣,随着⽅法的出栈⽽消失。
成员变量随着对象的创建⽽诞⽣,随着对象被垃圾回收机制回收⽽消失。
从作用域看:全局变量具有全局作用域.全局变量只需在一个源文件中定义,就可以作用于所有地源文件.当然,其他不包括全局变量定义地源文件需要用关键字再次声明这个全局变量.个人收集整理勿做商业用途静态局部变量具有局部作用域.它只被初始化一次,自从第一次初始化直到程序与你新内阁结束都一直存在,他和全局变量地区别在于全局变量对所有地函数都是可见地,而静态局部变量只对定义自己地函数体始终可见.个人收集整理勿做商业用途局部变量也只有局部作用域,他是自动对象,他在程序运行期间不是一直存在,而是只在函数执行期间存在,函数地一次调用结束后,变量就被撤销,其所占用地内存也被收回.个人收集整理勿做商业用途静态全局变量也具有全局作用域,他与全局变量地区别在于如果程序包含多个文件地话,他作用于定义它地文件里,不能作用到其他文件里,即被关键字修饰过地变量具有文件作用域.这样即使两个不同地源文件都定义了相同地静态全局变量,他们也是不同地变量.个人收集整理勿做商业用途从分配内存空间看:全局变量、静态局部变量、静态全局变量都在静态存储区分配空间,而局部变量在栈分配空间.全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式.这两者在存储方式上没有什么不同.区别在于非静态全局变量地作用域是整个源程序,当一个源程序由多个源文件组成时,非静态地全局变量在各个源文件中都是有效地.而静态全局变量则限制了其作用域,即只在定义该变量地源文件内有效,在同一源程序地其他源文件中不能使用它.由于静态全局变量地作用域局限于一个源文件内,只能为该源文件内地函数公用,因此可以避免在其他源文件中引起错误.个人收集整理勿做商业用途、静态变量会被放在程序地静态数据存储区里,这样可以在下一次调用地时候还可以保持原来地赋值.这一点是他与堆栈变量和堆变量地区别个人收集整理勿做商业用途、变量用告知编译器,自己仅仅在变量地作用域范围内可见.这一点是他与全局变量地区别.从以上分析可以看出,把局部变量改变为静态变量后是改变了他地存储方式,即改变了他地生存期.把全局变量改变为静态变量后是改变了他地作用域,限制了他地使用范围,因此这个说明符在不同地地方起地作用是不同地.个人收集整理勿做商业用途:、若全局变量仅在单个文件中访问,则可以讲这个变量修改为静态全局变量.、若全局变量仅在单个函数中使用,则可以将这个变量修改为该函数地静态局部变量.、全局变量、静态局部变量、静态全局变量都存放在静态数据存储区.、函数中必须要使用变量地情况:当某函数地返回值为指针类型时,则必须是地局部变量地地址作为返回值,若为类型,则返回为错指针.个人收集整理勿做商业用途个人收集整理勿做商业用途预备知识—程序地内存分配一个由编译地程序占用地内存分为以下几个部分栈区()—由编译器自动分配释放,存放函数地参数值,局部变量地值等.其操作方式类似于数据结构中地栈. 个人收集整理勿做商业用途堆区()—一般由程序员分配释放,若程序员不释放,程序结束时可能由回收 .注意它与数据结构中地堆是两回事,分配方式倒是类似于链表. 个人收集整理勿做商业用途全局区(静态区)()—,全局变量和静态变量地存储是放在一块地,初始化地全局变量和静态变量在一块区域,未初始化地全局变量、未初始化地静态变量在相邻地另一块区域. 程序结束后有系统释放个人收集整理勿做商业用途文字常量区—常量字符串就是放在这里地.程序结束后由系统释放程序代码区—存放函数体地二进制代码.一个正常地程序在内存中通常分为程序段、数据端、堆栈三部分.程序段里放着程序地机器码、只读数据,这个段通常是只读,对它地写操作是非法地.数据段放地是程序中地静态数据.动态数据则通过堆栈来存放.个人收集整理勿做商业用途在内存中,它们地位置如下:内存低端程序段数据段堆栈内存高端个人收集整理勿做商业用途堆栈是内存中地一个连续地块.一个叫堆栈指针地寄存器()指向堆栈地栈顶.堆栈地底部是一个固定地址.堆栈有一个特点就是,后进先出.也就是说,后放入地数据第一个取出.它支持两个操作,和.是将数据放到栈地顶端,是将栈顶地数据取出.在高级语言中,程序函数调用、函数中地临时变量都用到堆栈.为什么呢?因为在调用一个函数时,我们需要对当前地操作进行保护,也为了函数执行后,程序可以正确地找到地方继续执行,所以参数地传递和返回值也用到了堆栈.通常对局部变量地引用是通过给出它们对地偏移量来实现地.另外还有一个基址指针(,在芯片中是),许多编译器实际上是用它来引用本地变量和参数地.通常,参数地相对地偏移是正地,局部变量是负地.当程序中发生函数调用时,计算机做如下操作:首先把参数压入堆栈;然后保存指令寄存器()中地内容,做为返回地址();第三个放入堆栈地是基址寄存器();然后把当前地栈指针()拷贝到,做为新地基地址;最后为本地变量留出一定空间,把减去适当地数值.在函数体中定义地变量通常是在栈上,用, , 等分配内存地函数分配得到地就是在堆上.在所有函数体外定义地是全局量,加了修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义地变量表示在该文件中有效,不能到别地文件用;在函数体内定义地表示只在该函数体内有效.另外,函数中地""这样地字符串存放在常量区.对比:个人收集整理勿做商业用途性能栈:栈存在于中.栈是动态地,它地存储速度是第二快地.堆:堆位于中,是一个通用地内存池.所有地对象都存储在堆中.申请方式【栈】: 由系统自动分配. 例如,声明在函数中一个局部变量; 系统自动在栈中为开辟空间 .【堆】: 需要程序员自己申请,并指明大小,在中函数如( *)(); 在中用运算符如( *)(); 但是注意:、本身是在栈中地.申请后系统地响应栈【】:只要栈地剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出. 个人收集整理勿做商业用途堆【】:首先应该知道操作系统有一个记录空闲内存地址地链表,当系统收到程序地申请时,会遍历该链表,寻找第一个空间大于所申请空间地堆结点,然后将该结点从空闲结点链表中删除,并将该结点地空间分配给程序;另外,对于大多数系统,会在这块内存空间中地首地址处记录本次分配地大小,这样,代码中地语句才能正确地释放本内存空间.另外,由于找到地堆结点地大小不一定正好等于申请地大小,系统会自动地将多余地那部分重新放入空闲链表中.申请大小地限制栈【】:在下,栈是向低地址扩展地数据结构,是一块连续地内存地区域.这句话地意思是栈顶地地址和栈地最大容量是系统预先规定好地,在下,栈地大小是(也有地说是,总之是一个编译时就确定地常数),如果申请地空间超过栈地剩余空间时,将提示.因此,能从栈获得地空间较小. 个人收集整理勿做商业用途堆【】:堆是向高地址扩展地数据结构,是不连续地内存区域.这是由于系统是用链表来存储地空闲内存地址地,自然是不连续地,而链表地遍历方向是由低地址向高地址.堆地大小受限于计算机系统中有效地虚拟内存.由此可见,堆获得地空间比较灵活,也比较大.申请效率地比较栈【】:由系统自动分配,速度较快.但程序员是无法控制地. 个人收集整理勿做商业用途堆【】:是由分配地内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在下,最好地方式是用分配内存,他不是在堆,也不是在栈是直接在进程地地址空间中保留一快内存,虽然用起来最不方便.但是速度快,也最灵活.堆和栈中地存储内容栈【】:在函数调用时,第一个进栈地是主函数中后地下一条指令(函数调用语句地下一条可执行语句)地地址,然后是函数地各个参数,在大多数地编译器中,参数是由右往左入栈地,然后是函数中地局部变量.注意静态变量是不入栈地. 个人收集整理勿做商业用途当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存地地址,也就是主函数中地下一条指令,程序由该点继续运行.堆【】:一般是在堆地头部用一个字节存放堆地大小.堆中地具体内容有程序员安排.存取效率地比较[] "";* "";是在运行时刻赋值地;而是在编译时就确定地;但是,在以后地存取中,在栈上地数组比指针所指向地字符串(例如堆)快.比如:(){;[] "";* "";[];[];;}对应地汇编代码: [];[][]: [];[][][]第一种在读取时直接就把字符串中地元素读到寄存器中,而第二种则要先把指针值读到中,在根据读取字符,显然慢了.小结:堆和栈地区别可以用如下地比喻来看出:使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他地好处是快捷,但是自由度小.使用堆就象是自己动手做喜欢吃地菜肴,比较麻烦,但是比较符合自己地口味,而且自由度大.个人收集整理勿做商业用途。
C语言的变量一、全局变量和局部变量按照变量的有效作用范围可划分为局部变量和全局变量。
局部变量是在一个函数内部定义的变量,该变量只在定义它的那个函数范围以内有效,在此函数之外局部变量就失去意义了,因而也不能使用这些变量了。
不同的函数可以使用相同的局部变量名,由于他们的作用范围不同,不会相互干扰。
函数的形式参数也属于局部变量。
在一个函数内部的复合语句中也可以定义局部变量,该局部变量只在该复合语句中有效。
全局变量是在函数外部定义的变量,又称外部变量。
全局变量可以为多个函数共同使用,其有效的作用范围是从它定义的位置开始到整个程序文件结束为止。
如果全局变量定义在一个程序文件的开始处,则在整个程序文件范围内都可以使用它。
如果一个全局变量不是在程序文件的开始处定义的,但又希望在它的定义点之前的函数中引用该变量,这时应该在引用该变量的函数中用关键字extern将其说明为“外部变量”。
另外,如果在一个程序模块文件中引用另一个程序模块文件中定义的变量时,也必须用extern进行说明。
外部变量说明与外部变量定义是不同的。
外部变量定义只能有一次,定义的位置在所有函数之外,而同一个程序文件中的外部变量说明可以有多次,说明的位置在需要引用该变量的函数之内。
外部变量说明的作用只是声明该变量是一个已经在外部定义过了的变量而已。
如果在同一个程序文件中,全局变量与局部变量同名,则在局部变量的有效作用范围之内,全局变量是不起作用的,也就是说,局部变量的优先级比全局变量的高。
在编写C语言程序时,不是特别需要的地方就不要使用全局变量,二应当尽可能的使用局部变量。
这是因为局部变量只有在使用它时,才为其分配内存单元,二全局变量在整个程序的执行过程中都要占用内存单元。
另外,如果使用全局变量过多,在各个函数执行时都有可能改变全局变量的值,使人们难以清楚的判断出在各个程序执行点处全局变量的值,这样会降低程序的通用性和可读性。
还有一点需要说明,如果程序中的全局变量在定义时赋给了初值,按ANSI C标准规定,在程序进入主函数之前必须先对该全局变量进行初始化。
C语言基础知识1.每个C程序有且只有一个主函数main(),且程序必须从main()函数开始执行,并在main()函数中结束。
2.在C语言中,用e来表示科学计数法时,规定在e的前面必须有数字,后面必须为整数。
3.用单引号括起来的一个字符常量只能存放一个字符;C语言中没有字符串变量,只能用字符数组来存储字符串。
4.外部变量在编译时由系统分配永久的内存空间,所以外部变量的类型不是自动存储类别。
5.在一个函数内的复合语句中定义的变量,只能在这个复合语句范围内有效。
6.用sizeof(int)计算int类型数据的字节数。
7.C语言运行时,首先系统检查语法的正误,再运行程序的语法;C语言中,可以在一个函数中嵌套一个函数,但是不能在一个函数中定义一个函数;只有在函数外部定义的函数才是外部函数;C语言的子程序有过程和函数两种。
8.预处理命令行的位置没有规定,只是习惯放在前面;在源文件中的可以有多条预处理命令,但一行只能写一条;宏名的大写只是习惯性的表示;宏替换不仅不占用运行时间还不分配内存空间。
9.feof函数的作用是检查文件是否结束,当结束时返回的值为非零,否则为零。
10.当定义了数组后,在给其赋值时,不能直接把字符串赋给数组名。
11.在赋值表达式中,赋值运算符“=”右侧不能为表达式;在求余运算符中的两侧都必须为整型;在强制类型转换时,类型名应用括号括起来。
12.静态局部变量,只有当程序结束后,其值才释放。
13.当调用函数时,实参是一个数组名,则向函数传送的是数组每一个元素的地址。
14.算法的特点为有零个或多个输入,有一个或多个输出,当相同的输入时,其结果相同;算法正确的程序最终一定会结束。
15.在C语言中,预处理命令行都以“#”开头;当需要时才用#include<stdio.h>;预处理的作用就是实现宏定义和条件编译。
16.当数组元素的下标超出了定义的下标范围时,系统不给出“下标越界”的字样,而是得出错误的答案,因此在编程时务必检查下标是否越界。
栈区,堆区,全局区,文字常量区,程序代码区内存管理(1)一、预备知识—程序的内存分配一个由C/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
- 程序结束后由系统释放。
4、文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放5、程序代码区—存放函数体的二进制代码。
二、例子程序//main.cpp int a = 0; 全局初始化区char *p1; 全局未初始化区main() { int b; 栈char s[] = "abc"; 栈char *p2; 栈char *p3 = "123456"; 123456/0在常量区,p3在栈上。
static int c =0;全局(静态)初始化区p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456/0放在常量区,编译器可能会将它与p3所指向的"123456" 优化成一个地方。
}二、堆和栈的理论知识2.1申请方式stack:由系统自动分配。
例如,声明在函数中一个局部变量int b; 系统自动在栈中为b开辟空间heap:需要程序员自己申请,并指明大小,在c中malloc函数如p1 = (char *)malloc(10);在C++中用new运算符如p2 = new char[10];但是注意p1、p2本身是在栈中的。
2019CC++《阿⾥》⾯试题总结⼀、C和C++的区别是什么?C是⾯向过程的语⾔,C++是在C语⾔的基础上开发的⼀种⾯向对象编程语⾔,应⽤⼴泛。
C中函数不能进⾏重载,C++函数可以重载C++在C的基础上增添类,C是⼀个结构化语⾔,它的重点在于算法和数据结构。
C程序的设计⾸要考虑的是如何通过⼀个过程,对输⼊(或环境条件)进⾏运算处理得到输出(或实现过程(事务)控制),⽽对于C++,⾸要考虑的是如何构造⼀个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。
C++中struct和class除了默认访问权限外,别的功能⼏乎都相同。
⼆、关键字static、const、extern作⽤static和const的作⽤在描述时主要从类内和类外两个⽅⾯去讲:static关键字的作⽤:(1)函数体内static变量的作⽤范围为该函数体,该变量的内存只被分配⼀次,因此其值在下次调⽤时仍维持上次的值;(2)在模块内的static全局变量和函数可以被模块内的函数访问,但不能被模块外其它函数访问;(3)在类中的static成员变量属于整个类所拥有,对类的所有对象只有⼀份拷贝;(4)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因⽽只能访问类的static成员变量。
const关键字的作⽤:(1)阻⽌⼀个变量被改变(2)声明常量指针和指针常量(3)const修饰形参,表明它是⼀个输⼊参数,在函数内部不能改变其值(4)对于类的成员函数,若指定其为const类型,则表明其是⼀个常函数,不能修改类的成员变量(const成员⼀般在成员初始化列表处初始化)(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为”左值”。
extern关键字的作⽤:(1)extern可以置于变量或者函数前,以标⽰变量或者函数的定义在别的⽂件中,提⽰编译器遇到此变量和函数时在其他模块中寻找其定义。
最近工作之余,发现了两个自己在C语言学习中的难点,一个是字符串指针和字符数组的区别,一个就是静态全局变量、静态局部变量、全局变量和局部变量的区别,在网上查了不少资料,收获良多,现在与大家分享,有错误的地方请大家指正!
以下程序用VC++6.0调试
先说说字符串指针和字符数组的区别
1.相同点:
/* 用字符数组实现字符串操作*/
main( )
{
char str[]="Welcome to study C !";
int i;
printf("%s\n",str);
for (i=0;i<=7;i++)
printf("%c",str[i]); //用*(str+i)也行
printf("\n");
}
/* 用字符指针实现字符串操作*/
main()
{
char *str="Welcome to study C !";
int i;
printf("%s\n",str);
for(i=0;i<=7;i++)
printf("%c",*(str+i)); //用str[i]也行
printf("\n");
}
2.不同点:
a)赋值方式不同,字符数组只能对各个元素分别赋值,而字符指针只需赋给字符串的
首地址就可以了。
如: char *str;
str="Welcome to study C !";
以下对字符数组的赋值是错误的:
char str[80];
str[ ]="Welcome to study C !";
b)字符指针指向字符串,"hello"是一个字符串常量,与之相关联的内存空间位于内
存的只读部分,如:
char ch[] = "china\n";
char *p;
char *pp = "CHINA\n";
p = ch;
*(p+2) = 'h';//就是可以的
*(pp+2) = 'h';//此处在编译时不会出错,在执行的时候会出错
c) 函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通的指针类型,
对于void func (char sa[100],int ia[20],char *p),则sa的类型为char*,而不是char[100]
类型
下面介绍一下字符串常量和字符串变量:
1.字符串常量:
a)定义:是一对双引号括起来的字符序列
b)字符串包含的字符个数:不包括系统自动赋的’\0’,转义字符算1个
c)所占的字节数:字符串所包含的字符个数加1
d)长度:从第一个字符到第一个’\0’之间的字符个数,哪怕’\0’就在原字符串中
e)无论字符串常量还是字符串变量,空字符串可以存在””,而空字符是错误的’’
2.字符串变量:
a)C语言本身没有设置一种类型来定义字符串变量,字符串的存储完全依赖于字符数
组,但字符数组又不等于是字符串变量,例如:
Char str[] = {‘a’,’b’,’c’,’\0’};是str[4],是字符串
Char str[] = {‘a’,’b’,’c’};是str[3],是字符数组
Char str[7] = “string!”;可能破坏其他数据
b)在scanf,printf,gets,puts中的str不用写成str[10],只能写成str
下面介绍下静态全局变量,静态局部变量,全局变量,局部变量的区别
1.从作用域看:全局变量具有全局作用域。
全局变量只需在一个源文件中定义,就可以作
用于所有的源文件。
当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。
2.静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行
结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
3.静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,
它作用于定义它的文件里,不能作用到其它文件里,即被static 关键字修饰过的变量具有文件作用域。
这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。
4.从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,
而局部变量在栈里分配空间。
(扩展内存分配)
5.把局部变量改变为静态变量后是改变了它的存储方式即增加了它的生存期。
把全局变量
改变为静态变量后是改变了它的作用域,限制了它的使用范围。
程序的内存分配
1.程序占用的内存分为以下几个部分
a)栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
b)堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS
回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
c)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在
相邻的另一块区域。
- 程序结束后由系统释放。
d)文字常量区:常量字符串就是放在这里的。
程序结束后由系统释放
e)程序代码区:存放函数体的二进制代码。
2.例子程序
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456\0在常量区,p3在栈上。
static int c =0;全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"
优化成一个地方。
}
因此static 这个说明符在不同的地方所起的作用是不同的。
若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static 变量(这样的函数被称为:带“内部存储器”功能的的函数)
函数中必须要使用static 变量情况:比如当某函数的返回值为指针类型时,则必须是static 的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
static 全局变量:改变作用范围,不改变存储位置;static 局部变量:改变存储位置,不改变作用范围;静态函数:在函数的返回类型前加上static 关键字,函数即被定义为静态函数,只能在声明它的文件当中可见,不能被其它文件使用。
初始化
如果括号中提供的处置个数大于数组长度,则会出错。
如果初值小于数组长度,则将字符赋值给数组中前面的对应元素,其余元素自动填充空字符‘\0’。
格式化输出字符串时,输出项是字符数组名,不能写成数组中的元素。
输入函数的输入项直接写数组名,不写地址符&。
输入函数遇到空格认为结束。
两个字符数组变量不能直接赋值,只能通过移动下标操作字符数组中的每个元素进行分别赋值;两个字符值指针,可以直接赋值,即把一个字符指针所指向的地址赋值给另一个指针,
则两个指针指向的同一个地址。
字符数组和字符串两者之间不能直接赋值。
严格的说两个表达的意思是不完全一样的,因为前者是个字符串指针,这个指针S1所存的地址就是存储字符串前8个字节即hello/n/n/n的那个地址。
而后者是字符数组。
每个字符都有一个独立的地址。
见图示。
字符串变量:在c中是没有这个概念的,c中如果想将一个字符串存放到变量中,必须使用字符数组,就是用一个字符型数组存放一个字符串,一些自己的保护代码,通过软件手段将这段内存软保护起来。
这种保护在汇编级别可以轻松突破,其保护也就无效了。