指针与数组的初始化问题
我们看看接下来的程序,说明一下数组和指针初始化中的问题
#include<stdio.h>
int main() {
char* p = "hello";//把hello字符常量的首地址赋值给p
char c[10] = "hello";//等同于strcpy(c,"hello");
//p[0] = 'H';//非法的,因为p[0]所对应的是字符常量h,常量不可以改变值
puts(p[0]);
c[0] = 'H';
puts(c[0]);
p = 'world';//因为p是指针变量,所以它的地址值是可以从新赋值的。
//c = 'world';//非法的,因为我们把数组看似指针常量,不可以从新赋值。
}
其实之前我们说的进程地址空间不仅仅有堆和栈空间,还有字符常量区等等,如下图
1.为什么p[0] = 'H’是非法的?
"hello"属于字符常量。前面我们说过内存的权限我们常用的无非就是可读可写不可读不可写之间组合而字符常量区的权限是只读不可写的,因此p[0] = ‘H’;这个操作是非法的。
2.那为什么p = 'world’是可以的但是c = 'world’为数组赋值又是非法的呢?
因为p是指针变量,所以它的地址值是可以从新赋值的。p = 'world’只是把world的首地址赋给p而已
但是c是数组名,我们把数组名看似指针常量。一开始赋值之后,后面常量不可以从重新赋值了。因此数组变量名不可以进行自增、自减等等操作
二级指针(了解)
我们知道一级指针的使用场景是传递与偏移,服务的对象是整型变量、浮点型变量、字符型变量等。
二级指针也是一种指针,其作用自然也是传递与偏移,其服务对象更加简单,即只服务于一级指针的传递与偏移。
函数
函数的定义
**一个C程序由一个主函数和若干其他函数构成。**一个较大的程序可分为若干程序模块,每个模块实现一个特定的功能。在高级语言中用子程序实现模块的功能,而子程序由函数来实现。
结构如下一个fun.h头文件 一个main.c主函数 一个fun.c子函数。
为什么要分开写?
分开写是因为便于管理和添加新内容。因为我们一般开发项目都是要分开功能模块写的。一个源文件中有多个子函数但是只能有一个主函数
程序内容如下:
fun.h
#include<stdio.h> //stdio.h系统自己定义的函数,例如scanf、printf之类
int startprint(int i);//函数声明
void print_message();//函数声明
fun.c
#include "fun.h"
int startprint(int i) {
printf("***********************");
printf("printfstart i=%d\n", i);
return i + 3;
}
void print_message() {
printf("this is print_message function\n");
startprint(3);
}
main.c
#include "fun.h"
int main() {
int a = 10;
a = startprint(a);
print_message();
startprint(a);
return 0;
}
结果
过程如下
常见问题
头文件有什么用?
头文件就是为了声明函数stdio.h系统和自己定义的函数,以便我们使用函数功能。
例如scanf、printf之类这些都是系统自己定义好的,我们使用#include<stdio.h>就是为了引入这些函数
而int startprint(int i);和void print_message();都是我们自己定义的函数,要单独声明。
递归
递归就是函数自己调用自己
比如接下来的题目:计算n的阶乘
程序如下:
#include<stdio.h>
//函数自己调用自己就是递归
int f(int n) {
if (1 == n) {
return 1;
}
return n * f(n-1);//递归
}
int main() {
int n;
printf("请输入n的数字:");
scanf("%d", &n);
int ret = f(n);
printf("\n%d的阶乘为:%d\n", n, ret);
}
全局变量
定义:
函数之外定义的变量称为外部变量.外部变量可以为本文件中的其他函数共用,它的有效范围是从定义变量的位置开始到本源文件结束,所以也称全程变量.
它在进程空间的位置如下:
关于全局变量需要注意如下几点:
(1)全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。
(2)使用全局变量过多会降低程序的清晰性。在各个函数执行时都可能改变外部变量的值,程序容易出错,因此要有限制地使用全局变量。
(3)因为函数在执行时依赖于其所在的外部变量,如果将一个函数移到另一个文件中,那么还要将有关的外部变量及其值一起移过去。然而,如果该外部变量与其他文件的变量同名,那么就会出现问题,即会降低程序的可靠性和通用性。C语言一般要求把程序中的函数做成一个封闭体,除可以通过“实参→形参”的渠道与外界发生联系外,没有其他渠道。
局部变量与全局变量的区别
前面介绍了全局变量,之前我们学过局部变量,它们有什么不一样呢?
首先先来了解局部变量的定义。
局部变量的定义
在一个函数内部定义的变量称为内部变量。它只在本函数范围内有效,即只有在本函数内才能使用这些变量,故也称局部变量。
关于局部变量需要注意如下几点:
(1)主函数中定义的变量只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。
(2)不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。
(3)形参也是局部变量。
(4)在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称“分程序”或“程序块”,例如:
int main(){
int i = 10
{
int j = 5//局部变量的有效范围是离自己最近的花括号
}
}
注意:
1.局部变量与全局变量的区别就是在于定义位置和作用范围的不同
2.局部变量一般是在栈中或者堆中
全局变量是在数据区的.data(初始化过或者不等于0)或者.bss(未初始化或者等于0)里
3.全局变量尽量不要定义太多,因为它是变量又是全局有效,很容易导致数据出错