变量作用域
C语言变量作用域
1. 如果是局部变量和全局变量同名,那么在访问变量时候,采用就近原则
会现在局部变量中寻找,找不到再去全局变量中找
2. 在函数中不能访问其他函数中定义的局部变量
3. 在函数中可以访问全局变量
4. 多个函数可以共享一个全局变量
字符串
- 基本概念
/*
* 1. 字符串是什么?
* 将字符串在一起就是字符串,在C语言中字符串就是一个特殊的数组而已
*
* 2. 特殊点:
* 如果想要用数组来表示字符串,那么数组必须是char类型的,而且最后一个元素
* 必须是\0
*
* 3. 由于字符串比较特殊
* 所以在C语言中除了可以用字符数组来表示字符串,还可以用""来表示字符串
*
*/
char str1[] = {'w', 'j', 'n', '\0'}; //字符串以'\0'结尾
char str2[] = {'w', 'j', 'n'}; //不是字符串,是字符数组
//赋值的同时部分初始化,没有初始化的元素会自动赋值为0
char str3[10] = {'w', 'j', 'n', '\0'};
chr str4 = "wjh";
printf("%s\n", str);
- 字符串内存分析
//两者在内存中存储的状态
char str1[] = {'w', 'j', 'n', '\0'}; //字符串
char str2[] = {'w', 'j', 'n'}; //字符数组
- 字符串输出和输入
字符串输出: puts(str); 字符串输入: gets(ch);
/*
* 字符串输出和输入问题
*/
//1. 字符串输出
char str[] = "lnj";
//1.1 printf("%s"),%s会从数组的第0个元素开始打印,直到遇到\0位置
// 这种输出不会自动换行需要\n,还可以添加自定义内容
printf("%s\n", str);
//1.2 puts输出会自动换行,但是不能自定义添加内容
puts(str);
//2. 字符串输入
char ch[10];
//2.1 scanf("%s", &ch);接收字符串,输入的数据中不能有空格/TAB/回车,系统会将他们默认为结束字符
//scanf("%s", &ch);
//printf("%s\n", ch);
//2.2 gets接收方式
// 可以输入空格TAB符号
gets(ch);
printf("%s\n", ch);
- 字符串系统函数
注意点: 使用此类函数必须在头部导入#include
/*
* 字符串长度计算 strlen();
*/
char str[] = "niuzi";
//注意点: 这种计算字符串长度不包括\0字符,而且还能计算出字符串中存储字符数,但是使用系统函数需要在头部导入#include
int len = strlen(str);
printf("%i\n", len); // 5
#include
int main()
{
/*
* 字符串拼接
* strcat(ch1,ch2),传入两个数组,会将后面字符串数组拼接到前面
* 注意点: 前面的数组必须足够长,能够容纳两个
*/
char str1[10] = "niuzi";
char str2[] = "wjh";
strcat(str1, str2);
printf("%s\n", str1);
printf("%s\n", str2);
return 0;
}
include
#include
void myStrncar(char dest[], char src[], int count);
int main()
{
/*
* 字符串拼接
* strncat(dest, src, count);
* 会将src中count个字符拼接到dest后面
*/
char str1[20] = "niuzi";
char str2[10] = "888666";
strncat(str1, str2, 2);
printf("%s\n", str1);
return 0;
}
/*
* 字符串拷贝
* 会将后面的字符拷贝到前面,覆盖前面原有的内容
*/
char str1[20] = "wjh";
char str2[20] = "haha";
strcpy(str1, str2);
printf("%s\n", str1);
/*
* 字符串比较
* 会依次从第0个索引开始,取出第一个数组和第二个数组中每个元素
* 如果str1当前元素大于str2当前元素,那么返回一个正数
* 如果str1当前元素小于str2当前元素,那么返回一个负数
* 如果str1当前元素等于str2当前元素,那么返回一个0
*
*/
char str1[10] = "124";
char str2[10] = "124";
int res = strcmp(str1, str2);
printf("%i\n", res);
指针
- 指针变量
/*
* 指针变量:
* 指针变量和普通变量一样,都是用来保存数据的,只不过和普通变量有一点区别
* 普通变量可以保存基本数据类型,指针变量只能保存内存地址,简言之就是保存内存地址的变量
* 格式:
* 数据类型 *变量名称;
*/
int num = 7;
int *p; //定义一个指针变量
//注意点: 所有指针变量占用内存的大小是一样的,与指针数据变量数据类型无关
// 在32位编译器中,占用4个字节
// 在64位编译器中,占用8个字节
// 只要一个变量存储了另外一个变量的内存地址,那么我们可以说这个变量指向了另外一个变量
// 而且我们可以根据这个内存地址找到另外变量的内存地址,从而操作这部分内存
p = # // 将num变量占用内存最小的地址存储到指针变量P中
printf("%p\n", p);
printf("%p\n", &num);
printf("%p\n", &p); //取出p自己的地址
-
指针内存
指针变量操作数据
/*
* 指针变量操作存储地址数据
*/
int num = 8;
int *p;
p = #
//1. 只要一个变量指向了另外一个变量,就可以通过*变量名称的方法,操作另外一个变量的内存空间
*p = 10; //在指针前面加上*号代表访问指针指向的那块内存
printf("%i\n", num); //10
//2. 指针只能保存地址,不能存储其他的值
//3. 一个变量地址可以被多个指针指向
//4. 指针的指向可以改变,后赋值的地址会覆盖前面赋值的地址
//5. 定义指针变量时候,前面的数据类型,一定要和将来保存的变量前面的数据类型一致
int num2 = 10;
int *p1; // 正确 错误写法: double *p1;
p1 = &num2;
- 指针的类型
注意: 如果函数的形参是数组或者是指针,那么就可以在函数中修改外界传入变量的值
#include
void change(int *num);
int main()
{
/*
* 指针类型:
* 由于指针变量指向的是某一个变量占用的存储空间的首地址
* 所以在获取指向变量中存储数据的时候,指针是不知道要获取多少个字节的数据的
* 所以指针变量的数据类型的作用,就是告诉指针,在获取指向变量的数据时候,需要
* 获取几个字节的数据
*
* int *p 将来获取p指向的那个变量的数据的时候,需要获取4个字节的数据
*/
int num = 10;
change(&num); //注意参数如果是指针类型,此处应该传入地址
printf("%i\n", num); //666
return 0;
}
//结论: 如果函数的形参是数组或者是指针,那么就可以在函数中修改外界传入变量的值
void change(int *num){
*num = 666;
}
- 多级指针
注意点: 多级指针取值格式: **p,几级指针前面就加几个*
/*
* 多级指针:
* 指针中保存的是其他指针的地址
*
* 如何定义多级指针
* 在保存的指针变量的基础上加上*即可 int *p --> int **pp
*
* 定义指针规则:
* 1. 将要指向的变量的定义拷贝过来
* 2. 再将拷贝过来的代码的类型和变量名称中间加上*
* 3. 修改变量名称
*/
int num = 10;
int *p; // 一级指针
p = #
int **pp; //二级指针
pp = &p;
// **pp -> *p ->num 三个相等
printf("&num = %p\n", &num); //0028FEB8
printf("p = %p\n", p); //0028FEB8
printf("&p = %p\n", &p); //0028FEB4 一级指针对应本身的地址
printf("&pp = %p\n", &pp); //0028FEB0 二级指针对应本身的地址
printf("pp = %p\n", pp); //0028FEB4 二级指针存储的是一级指针自身的地址
printf("*pp = %p\n", *pp); //0028FEB8
printf("**pp = %i\n", **pp); //10 取出num内存的值
int ***ppp; //三级指针
ppp = &pp;
- 指针与数组
/*
* 指针和数组
*
* 数组名称保存的就是数组占用内存最小的那个地址
* 既然数组名称是保存地址,指针也可以保存地址,所以指针也可以指向数组
*
* 结论: 如果利用指针保存数组的地址之后,那么p = ages = &ages;
*/
int ages[3] = {1,3,5};
printf("%i\n", ages[1]); //3
int *p;
p = &ages;
p[1] = 333;
printf("%i\n", p[1]); //333
- 指针加减法
/*
* 指针加减法
* 应用场景: 一般都是用在数组中
* 指针变量+1,加的就是指针变量类型占用的字节数
* -1操作一般都不会用到
*
*/
int arr[3] = {1,3,5};
int *p = &arr;
printf("%i\n", *p); // 1 默认指向是数组最小的地址然后取出4个字节
printf("%i\n", *(p+1)); //3
printf("%i\n", *(p+2)); //5
printf("%i\n", *p++); //1
printf("%i\n", *p++); //3
printf("%i\n", *p++); //5
- 指针和字符串
/*
* 指针定义字符串
* 字符串本身就是数组,所以指针也可以定义字符串
*/
// char str1[] = "hui";
// //char *str2 = "hui";
// printf("%s\n", str1);
// printf("%s\n", str2);
/*
* 利用数组和指针定义字符串的区别:
* 1. 存储位置不同
* 如果是通过数组定义的字符串,那么存储在内存当中
* 如果是通过指针定义的字符串,那么存储在内存的常量区中
* 2.存储空间地址不同
* 如果是通过数组定义的字符串,每次定义都要重新开辟存储空间
* 如果是通过指针定义的字符串,重复定义不会重新开辟存储空间
* 3.由于在内存中存储的位置不一样,所以特性也不一样
* 如果是通过数组定义的字符串,我们可以手动修改
* 如果是通过指针定义的字符串,我们不能手动修改
*/
char *str1 = "lnj";
char *str2 = "lnj";
str1[1] = 's'; //不能修改
printf("%s\n", str1);
// printf("%p\n", str1); //地址一样
// printf("%p\n", str2);
int main()
{
//1. 接收字符串的时候,只能通过字符数组不能通过字符指针
//2. 学习指针之后,建议将过去传入数组类的形参修改位指针类型
/*
* 如果函数中返回的字符串类型是通过数组创建的,那么外界无法获取
* 如果函数中返回的字符串类型是通过指针创建的,那么外界可以获取
* 这是因为指针类型存储数组存在常量区当中
*/
char *str;
scanf("%s",str); //这种错误
return 0;
}
void test(int *arr){ //这样方式接收数组类型参数
}
char* demo(){
char *str = "wjh";
return str;
}
- 指针变量特点
1. 可以用来保存数据
2. 可以当做形参
3. 可以用来当做返回值