标签:oca 输入 大小 void 指针和一维数组 学习 逻辑 更改 相对
#include <stdio.h>
/*
总结:
一维数组名
一维数组名是个指针常量
它存放的是一维数组第一个元素的地址
*/
int main(void)
{
int a[5]; //a是数组名 5是数组元素的个数 元素就是变量 a[0] -- a[4]
// int a[3][4]; //3行4列 a[0][0]是第一个元素 a[i][j]第i+1行j+1列
int b[5];
//a = b;//error a是常量
printf("%#X\n", &a[0]);
printf("%#X\n", a);
return 0;
}
常量是不能被改变的,也就是说,一维数组名是不能被改变的。
数组名a存放的是一维数组第一个元素的地址,也就是a = &a。
**如果p是个指针变量,则p[i]永远等价于*(p+i)**
# include <stdio.h>
int main(void)
{
int a[5] = {1,2,3,4,5};
int i;
for (i=0; i<5; ++i)
printf("%d\n", a[i]); //a[i] == *(a+i)
return 0;
}
# include <stdio.h>
/*
a是个指针变量,所以上面局部函数f的pArr则要定义成指针函数才可以,而len则是int类型。代表接收的是整型的数字。
*/
//f函数可以输出任何一个一维数组的内容
void f(int * pArr, int len)
{
int i;
for (i=0; i<len; ++i)
printf("%d ", *(pArr+i) ); //*pArr *(pArr+1) *(pArr+2)
printf("\n");
}
int main(void)
{
int a[5] = {1,2,3,4,5};
int b[6] = {-1,-2,-3,4,5,-6};
int c[100] = {1, 99, 22, 33};
f(a, 5); //a是 int *
f(b, 6);
f(c, 100);
return 0;
}
/*
1、一定要明白 10行的pArr[3] 和17行 19行的a[3] 是同一个变量因为数组a的名称代表的是a的第一个元素的地址,所以在函数f中所定义的指针变量pArr和a是相同的,因为a也是指针类型。
2、也就是说pArr=a=a[0],pArr[1]=a[1]=*(pArr+1)=*(a+1),pArr[2]=a[2]=*(pArr+2) =*(a+2).所以在f函数中pArr[3]=a[3],所以第二个printf输出的结果是88.总结:pArr[i] = a[i] = *(pArr+i) = *(a+i)
3、在没有学习指针时,可将a[3]认为是数组中第4个元素,这里下标也当成指针了,从首元素开始向后移动3个,即指向第4个元素。
*/
# include <stdio.h>
void f(int * pArr, int len)
{
pArr[3] = 88; //10行
}
int main(void)
{
int a[6] = {1,2,3,4,5,6};
printf("%d\n", a[3]); //17行
f(a, 6);
printf("%d\n", a[3]); // 19行
return 0;
}
/*
因为数组a的名称代表的是a的第一个元素的地址,所以在函数f中所定义的指针变量pArr和a是相同的,因为a也是指针变量类型。也就是说pArr=a=a[0],pArr[1]=a[1]=*(pArr+1)=*(a+1),pArr[2]=a[2]=*(pArr+2) =*(a+2).我们在f函数中修改数组的值,相当于修改主函数中相对应的值。
*/
# include <stdio.h>
void f(int * pArr, int len)
{
int i;
for (i=0; i<len; ++i)
printf("%d ", pArr[i]); //*(pArr+i) 等价于 pArr[i] 也等价于 b[i] 也等价于 *(b+i)
printf("\n");
}
int main(void)
{
int b[6] = {-1,-2,-3,4,5,-6};
f(b, 6);
b[i]
return 0;
}
# include <stdio.h>
int main(void)
{
char ch = 'A';
int i = 99;
double x = 66.6;
char * p = &ch;
int * q = &i;
double * r = &x;
printf("%d %d %d\n", sizeof(p), sizeof(q), sizeof(r));
return 0;
}
数组长度必须事先指定,而且只能是常整数,不能是变量
例子 int a[5]; //必须事先指定,而且只能是常整数int len = 5; int a[len];//error
2.传统形式定义的数组,该数组的内存程序员无法手动释放数组一旦定义.
系统为数组分配的内存空间就会一直存在,除非数组所在的函数运行终止。在一个函数运行期间,系统为该函数中的数组分配的空间会一直存在。直到该函数运行完毕时,数组的空间才会被系统自动释放(不是清零)。
例子:void f(void){ int a[5]={1,2,3,4,5};....}
//数组a 占20个字节的内存空间,程序员无法手动编程释放它,数组a只能在f()函数结束被系统释放
3、数组的长度一旦定义,数组长度就不能再更改。数组的长度不能在函数运行的过程中动态的扩充或缩小.
4、传统方式定义的数组不能跨函数使用
A函数定义的数组,只有在A函数运行期间才可以被其他函数使用,
但A函数运行完毕后,A函数中的数组将无法在被其他函数使用。
# include <stdio.h>
/*
代码实现(传统数组的缺陷)
*/
void g(int * pArr, int len)
{
pArr[2] = 88; //pArr[2] == a[2]
}
void f(void)
{
int a[5] = {1,2,3,4,5}; //20个字节的存储空间程序员无法手动编程释放它,
//它只能在本函数运行完毕时由系统自动释放
g(a, 5);
printf("%d\n", a[2]);
}
int main(void)
{
f();
return 0;
}
为什么需要动态分配内存
很好的解决的了传统数组的4个缺陷
/*
2009年11月17日10:21:31
malloc 是 memory(内存) allocate(分配)的缩写
*/
# include <stdio.h>
# include <malloc.h> //不能省
int main(void)
{
int i = 5; //分配了4个字节 静态分配 11 行
int * p = (int *)malloc(4); //12行
/*
1. 要使用malloc函数,必须添加malloc.h这个头文件
2. malloc函数只有一个形参,并且形参是整型
3. 4表示请求系统为本程序分配4个字节
4. malloc函数只能返回第一个字节的地址
5. 12行分配了8个字节, p变量占4个字节, p所指向的内存也占4个字节
6. p本身所占的内存是静态分配的, p所指向的内存是动态分配的
*/
*p = 5; //*p 代表的就是一个int变量, 只不过*p这个整型变量的内存分配方式和11行的i变量的分配方式不同
free(p); //freep(p)表示把p所指向的内存给释放掉 p本身的内存是静态的,不能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放
printf("同志们好!\n");
return 0;
}
# include <stdio.h>
# include <malloc.h>
void f(int * q)
{
//*p = 200; //error
//q = 200; //200不是整型变量的地址,q只能存放整型变量的地址
//**q = 200; //error
*q = 200;
//free(q); //把q所指向的内存释放掉 本语句必须的注释掉,否则会导致第20行的代码出错
}
int main(void)
{
int * p = (int *)malloc(sizeof(int)); //sizeof(int)返回值是int所占的字节数
*p = 10;
printf("%d\n", *p); //10
f(p); //p是int *类型
printf("%d\n", *p); //200 第20行
return 0;
}
图解
# include <stdio.h>
# include <malloc.h>
int main(void)
{
int a[5]; //如果int占4个字节的话,则本数组总共包含有20个字节,每四个字节被当做了一个int变量来使用
int len;
int * pArr;
int i;
//动态的构造一维数组
printf("请输入你要存放的元素的个数: ");
scanf("%d", &len);
pArr = (int *)malloc(4 * len); //第12行 本行动态的构造了一个一维数组, 该一维数组的产度是len, 该数组的数组名是pArr, 该数组的每个元素是int类型 类似于 int pArr[len];
//对一维数组进行操作, 如:对动态一维数组进行赋值
for (i=0; i<len; ++i)
scanf("%d", &pArr[i]);
//对位一维数组进行输出
printf("一维数组的内容是:\n");
for (i=0; i<len; ++i)
printf("%d\n", pArr[i]);
free(pArr); //释放掉动态分配的数组
return 0;
}
1.动态数组长度不需要事先给定;
2.内存空间可以手动释放。
3.在程序运行中,动态内存空间大小可以通过realloc函数手动扩充或缩小
静态内存是由系统自动分配,有系统自动释放
静态内存是在栈分配的
动态内存是由程序员手动分配、手动释放
动态内存是在堆分配的
#### 多级指针代码实现
# include <stdio.h>
int main(void)
{
int i = 10;
int * p = &i; //p只能存放int类型变量的地址
int ** q = &p; //q是int **类型, 所谓int **类型就是指q只能存放int *类型变量的地址,
int *** r = &q; //r是int ***类型, 所谓int ***类型就是指r只能存放int ** 类型变量的地址,
//r = &p; //error 因为r是int *** 类型,r只能存放int **类型变量的地址
printf("i = %d\n", ***r); //输出结果是10 只有 ***r才表示的是i, *r或 **r或 ****r代表的都不是i
return 0;
}
多级指针代码实现2
#include <stdio.h>
//多级指针在函数中的应用
void f(int ** q)
{
**q = 100; //*q就是p
}
void g()
{
int i = 10;
int * p = &i;
printf("i = %d *p = %d\n", i, *p);
f(&p); //p是int *类型 &p就是int ** 类型
printf("i = %d *p = %d\n", i, *p);
}
int main(void)
{
g();
return 0;
}
/*
内存越界:程序访问了一个不该被访问的内存,函数内的静态空间,不能被其他函数调用访问。函数中的内存空间,随函数终止而被释放。内存空间释放后的内容不属于其他函数,其他函数无权限访问。但释放后的内存空间的地址是可以被其他函数读取的。但指针变量可以存贮任何函数中静态内存空间的地址,p都能存垃圾,p想存谁存谁。只是它此时已经没有权限读取(访问) i这个地址的数据了,出错。。
*/
# include <stdio.h>
void f(int ** q) //q是个指针变量,无论q是什么类型的指针变量,都只占4个字节
{
int i = 5;
//*q等价于p q和**q都不等价于p
//*q = i; //error 因为*q = i; 等价于 p = i; 这样写是错误的
*q = &i; // p = &i;
}
int main(void)
{
int *p; //13行
f(&p);
printf("%d\n", *p); //16行 本语句语法没有问题,但逻辑上有问题
return 0;
}
# include <stdio.h>
# include <malloc.h>
void f(int ** q) //*q等价p 已经声明了q的类型为int **
{
*q = (int *)malloc(sizeof(int)); //sizeof(数据类型) 返回值是该数据类型所占的字节数
//等价于 p = (int *)malloc(sizeof(int));
//q = 5; //error
//*q = 5; //p = 5;
**q = 5; //*p = 5;
}
int main(void)
{
int * p;
f(&p); //只有调用变量的地址,才能改变变量的值
printf("%d\n", *p);
//f函数中,没有free(q);所以动态空间仍然保留,动态空间中的内容可以被访问
return 0;
}
?
标签:oca 输入 大小 void 指针和一维数组 学习 逻辑 更改 相对
原文地址:https://www.cnblogs.com/Guard9/p/11082065.html