1、堆与栈、静态数据区
【堆栈的动态静态分配】
A,静态分配是指在编译阶段确定大小,由编译器进行分配。
栈的申请就是静态分配的。
B,动态分配是指在执行阶段确定大小。
堆的申请都是在执行过程中进行的,堆只能进行动态分配。堆在动态分配时,要申请连续的内存空间,释放后会产生碎片。
栈也可以使用动态分配。
C,堆是使用malloc()、calloc()、realloc()等函数动态分配的,而栈使用alloca()函数动态分配的内存空间,释放的时候由编译器自己释放。
#include<stdio.h>
char *myString()
{
char buffer[6] = {0};
char *s = "Hello World!";
for (int i = 0; i < sizeof(buffer) - 1; i++)
{
buffer[i] = *(s + i);
}
return buffer;
}
int main(int argc, char **argv)
{
printf("%s\n", myString());
return 0;
}
结果:空。buffer存在栈中,随着函数的的结束而消失。应该使用new。
int main()
{
char *p = "hello,world";
return 0;
}
p是局部变量,存在栈中;hello,world存在静态数据区
【new、malloc】
a、动态分配。都是在堆(heap)上进行动态分配内存。
b、初始化。用malloc不进行初始化,
new 进行初始化,取决于变量定义的位置,在函数体外定义的变量都初始化为0,在函数体内定义的内置类型变量都不进行初始化。
c、delete 会调用对象的destructor,而free 不会调用对象的destructor。
new使用方法
1、new单个对象
new在自由空间分配内存,但其无法为其分配的对象命名,因次是无名的,分配之后返回一个指向该对象的指针。
int *pi = new int; // pi指向一个动态分配的,未初始化的无名对象
此new表达式在自由空间构造一个int类型对象,并返回指向该对象的指针。
new是默认初始化的,这意味着内置类型或组合类型的对象的值是无定义的,而类类型对象将用默认构造函数进行初始化。
2、new(多个对象)数组
delete使用方法new分配的多个对象也是默认初始化。但可以对数组进行值初始化,方法就是:在大小之后添加一对空括号。
int *pia = new int[10]; // 10个未初始化int
int *pia2 = new int[10](); // 10个值初始化为0的int
1、回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。
2、关于 new[] 和 delete[],其中又分为两种情况:
(1) 基本数据类型分配和回收空间;基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;
(2) 自定义类型分配和回收空间。但是对于类对象数组,只能用 delete[],告诉编译器,释放的是一块内存,逐一调用析构函数,然后释放空间。
malloc系列函数1) malloc 函数: void *malloc(unsigned int size)
在内存的动态分配区域中分配一个长度为size的连续空间。
如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。
2)calloc 函数: void *calloc(unsigned int num, unsigned int size)
按照所给的数据个数和数据类型所占字节数,分配一个 num * size 连续的空间。
calloc申请内存空间后,会自动初始化内存空间为 0,但是malloc不会进行初始化,其内存空间存储的是一些随机数据。
3)realloc 函数: void *realloc(void *ptr, unsigned int size)
动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr,把ptr内存空间调整为size。
申请的内存空间不会进行初始化。
【静态区】
static:静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;存放在已初始化区;
2、数组、指针的加减运算
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
输出:2,5
分析:(1)a:数组名,是一个指针,也就是数组第一个元素的地址。*(a+1)等同于a[1],*(a+1)=2。
(2)&a+1:a是数组名,是一个指针,那么&a是什么呢?指针的地址,其指向a[5]数组这个内存块,所以 &a+1 指向数组最后一个元素的 下一个位置,故*(ptr-1)指向数组的最后一个元素。
char *ptr;
char myString[] = "abcdefg";
ptr = myString;
ptr += 5;
代码执行之后ptr指向的内容是?fg
int a[3];
a[0] = 0; a[1] = 1; a[2] = 2;
int *p, *q;
p = a;
q = &a[2];
则a[q - p] = 2
#include<stdio.h>
int main(void)
{
int n;
char y[10] = "ntse";
char *x = y;
n = strlen(x);
*x = x[n];
x++;
printf("x=%s\n",x);
printf("y=%s\n",y);
return 0;
}
输出:x=tse,y=
分析:n = strlen(x),此时n=4,因为x指向y数组,所以x[4]就是y[4]='\0',那么*x=x[n]就是把x指向的字符串首元素改为'\0',
x++之后x指向第二个字符t,所以第一个输出x=tse,而y遇到第一个字符就是'\0',所以结束,y输出为空
本题关键是*x = x[n],把最后一个元素赋值给首元素。
int main()
{
printf("\n");
int a[5] = {1, 3, 4, 5, 6};
int *p, **k;
p = a;
k = &p;
printf("%d", *(p++));
printf("%d", **k);
return 0;
}
输出:13
分析:注意*(p++),它与*p++一样,都是先运算*p,再运算p++,使得p的地址移动一位,所以是3。
【数组、指针大小】
void Func(char str_arg[100])
{
printf("%d\n", sizeof(str_arg));
}
int main(void)
{
char str[] = "Hello";
printf("%d\n", sizeof(str));
printf("%d\n", strlen(str));
char *p = str;
printf("%d\n", sizeof(p));
Func(str);
}
程序输出:6 5 4 4
分析:str数组名,sizeof(str)为数组的大小,注意这里不能把str当做指针;这一点也可以从strlen(str)看出;
指针的大小就是4;
函数参数为数组的话,数组会退化为指针,所以Func(str)=4。
在32位系统中:
char arr[] = {4, 3, 9, 9, 2, 0, 1, 5};
char *str = arr;
sizeof(arr) = 8
sizeof(str) = 4
strlen(str) = 5
char *p1= “123”, *p2 = “ABC”, str[50]= "xyz";
strcpy(str+2,strcat(p1,p2));
cout << str;
序的输出结果是?
出错
分析:p1,p2指向的是静态数据区,大小已经分配好了,无法使用strcat连接,会出错。
【指针的加减】
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
请问p1+5= 什么?
p2+5= 什么?
程序输出:801010 810014
分析:p1+5=p1+5*1=p1+5*sizeof(unsigned char)=p1+5*1=0x801000+ox5=0x801005
p2+5=p2+5*1=p2+5*sizeof(unsigned long)=p1+5*4=0x810000+20=0x810000+0x14=0x810014(进制转换)
#include <stdio. h>
main()
{
int c[6] = {10,20,30,40,50,60}, * p, * s;
p = c;
s = &c[5];
printf("%d\n", s-p );
}
程序运行后的输出结果是?
答案:5
4、数组指针与二维数组
(一)int a[3][4],下面哪个不能表示 a[1][1]?A、*(&a[0][0]+5)
B、*(*(a+1)+1)
C、*(&a[1]+1)
D、*(a[1]+1)
答案:C
解析:
在二维数组中a[1]表示的是a[1][0]的地址,数组在内存中连续存储,所以a[1]+1表示的是a[1][1]的地址,所以D可以取得正确的值;
指针操作*(a+1)与a[1]等价,所以B也可以取得正确的值;
二维数组在内存中是行优先存储的,所以A中a[0][0]的地址加5可以取得正确值;
C选项错误,应改为*(&a[1][0]+1),否则,则指向a[2][0]。
(二) 要使指针变量p指向2维数组A的第1个元素,正确的赋值表达式是()
p=A或p=A[0]
p=A[0]或p=A[0][0]
p=A[0]或p=&A[0][0]
p=A或p=&A[0][0]
答案:第三个选项
分析: A、p = A:它是行指针。在多维数组中,A表示第一维数组,不是第一个元素;
B、p = A[0]:它是指针。在二维数组中,指向的是二维数组的第一个元素;
C、p = &A[0][0]:A[0][0],它是数组元素,表示二维数组的第一个元素,所以可以p = &A[0][0]。
一维数组:数组名表示第一个元素
二维数组:数组名表示第一维数组,行指针;