C语言之数组与指针

*******数组首元素的地址 vs 数组首地址*******

/*
a: bff0660c
a+1: bff06610
&a: bff0660c
&a+1: bff06620
*/
int a[5] = {1,2,3,4,5};
printf("a: %x\n", a); //address of first element in the array
printf("a+1: %x\n", a+1); //address of second element in the array
printf("&a: %x\n", &a); //starting address of the array
printf("&a+1: %x\n", &a+1); //1 plus the ending address of the array

 

*******数组名和指针是不同的概念(可以用extern证明,见deepc2.c)*******

在一个地方定义为指针,另一各地方也只能声明为指针;在一个地方定义为数组,另一各地方也只能声明为数组;

数组和指针都可以指针或下标的形式访问。


*******指针数组与数组指针*******

int *p[10]; //指针数组。p先与[]结合,构成一个数组的定义,数组名为p,int*修饰的是数组的内容,即数组的每个元素类型为int*。

int (*q)[10] or int (*)[10] q; //数组指针。q先与*结合,构成一个指针的定义,指针变量名为q。int修饰的是数组的内容,即数组的每个元素类型为int。数组在这里并没有名字,是个匿名数组。所以,q是一个指向包含10个int型数据的数组的指针,即数组指针。

可推广至函数返回值 与 函数指针。

/*
b: bfb033a7
p1: bfb033a7
p2: bfb033a7
p1+1: bfb033ac
p2+1: bfb033ac
p3: bfb033a7
p4: bfb033a7
p3+1: bfb033aa
p4+1: bfb033aa
p5: bfb033a7
p6: bfb033a7
p5+1: bfb033b1
p6+1: bfb033b1
*/
char b[5] = {'A','B','C','D'};
printf("b: %x\n", b);

char (*p1)[5] = &b;
char (*p2)[5] = b; //incompatible type
printf("p1: %x\n", p1);
printf("p2: %x\n", p2);
printf("p1+1: %x\n", p1+1); //increase based on type of p1, not &b
printf("p2+1: %x\n", p2+1); //increase based on type of p2, not b

char (*p3)[3] = &b; //incompatible type
char (*p4)[3] = b; //incompatible type
printf("p3: %x\n", p3);
printf("p4: %x\n", p4);
printf("p3+1: %x\n", p3+1); //increase based on type of p3, not &b
printf("p4+1: %x\n", p4+1); //increase based on type of p4, not b

*******地址强制转换*******

 

//little endian: the least significant byte at lowest address.
//big-endian: the most significant byte at lowest address.
int checkSystem()
{
//union size is the largest size of its fields. And all fields are stored right from lowest address.
union check{
int i;
char ch; //stored at the lowest byte.
}c;

c.i = 1;
return (c.ch == 1);
}

int main()
{
/*
Little-Endian
value: 12345678 //output digits from highest byte to lowest byte
p[0]: 78 //'78' is the least significant byte. p[0] locates at the lowest address.
p[1]: 56
p[2]: 34
p[3]: 12 //'12' is the most significant byte. p[3] locates at the highest address.
ptr1[-1]: 4
*ptr2: 2000000 //output digits from highest byte to lowest byte, so '02' comes first. when big-endian, *ptr2: 0x100
*/
printf("%s\n", checkSystem()?"Little-Endian":"Big-Endian");

int i;
int value = 0x12345678;
printf("value: %x\n", value);
char *p = (char*)&value;
for(i=0; i<4;i++)
{
printf("p[%d]: %x\n", i, p[i]);
}

int a[4] = {1,2,3,4};//1: 0x00000001, 2: 0x00000002, 3: 0x00000002, 4: 0x00000004.
int *ptr1 = (int*)(&a+1); //ptr1 points to the ending address of array a: the integer right after array a.
int *ptr2 = (int*)((int)a+1); //ptr2 points to starting (low) address of the second byte of a[0]。 (int)a+1 与 (int*)a+1不同。

printf("ptr1[-1]: %x\n*ptr2: %x\n", ptr1[-1], *ptr2);
return 0;
}

*******二维数组*******

#include <stdio.h>

int main(int argc, char* argv[])
{
int a[5][5];
int (*p)[4];
p = a;
printf("a_ptr=%p, p_ptr=%p\n", &a[4][2], &p[4][2]);
printf("%p, %d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
printf("%p, %d\n", &a[4][2] - &p[4][2], &a[4][2] - &p[4][2]);
printf("%p, %d\n", 0x50-0x40, 0x50-0x40);
/*
*Output:
*a_ptr=0xbfcd5c50, p_ptr=0xbfcd5c40 //address difference: 16 bytes. &a[4][2] - &p[4][2] = 0x10
*0xfffffffc, -4 //pay attention to '%p' and '%d'.
*0x4, 4 //Why 4? It is pointer arithmetic. (int*)0xbfcd5c50-(int*)0xbfcd5c40 = (0xbfcd5c50-0xbfcd5c40)/sizeof(int) = 4.
*0x10, 16
*/
}

 

*******数组参数与指针参数*******

无法向函数传递一个数组。C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。

无法把指针变量本身传递给一个函数

void GetMemory0(char *p, int num)
{
p = (char*)malloc(num*sizeof(char));
}

char* GetMemory1(char *p, int num)
{
p = (char*)malloc(num*sizeof(char));
return p;
}

void GetMemory2(char **p, int num)
{
*p = (char*)malloc(num*sizeof(char));
}

int main(int argc, char* argv[])
{

char *str = NULL;

GetMemory0(str, 10); //str does not get the address allocated in GetMemory0. str是局部变量,调用时,编译器会做一份拷贝_str,并把_str传给GetMemory。所以GetMemory改变的只是_str。
//str = GetMemory1(str, 10); //str gets the address allocated in GetMemory1.
//GetMemory(&str, 10); //str gets the address allocated in GetMemory2.
if(str == NULL)
printf("str is still NULL\n");
else{
strcpy(str, "hello");
printf("str: %s\n", str);
free(str);
}
/* Output:
* str is still NULL
*/

return 0;
}

如何为str获取内存呢?两种办法。

第一: 用return。 GetMemory1.

第二: 用二级指针。 GetMemory2.

 

*******二维数组参数与二维指针参数*******

void fun(char a[3][4]);

void fun(char (*p)[4]);

void fun(char a[][4]);

 

void fun(char *p[4]);

void fun(char **p);

 

void fun(char a[3][4][5]);

void fun(char a[][4][5]);

void fun(char (*p)[4][5]);

 

*******函数指针*******

 

"char* (*func)(char* p1, char* p2)", but not  "char* (*)(char* p1, char* p2) func".

Example 1:

char* fun(char* p1, char* p2)
{
int i=0;
i=strcmp(p1, p2);
if(0==i)
return p1;
else
return p2;
}

int main(void)

{

char* (*pf1)(char* p1, char* p2);
pf1 = &fun;
printf("%s\n", (pf1)("aa", "bb")); //pf1 vs *pf1
printf("%s\n", (*pf1)("aa", "bb"));
/* Output:
* bb
* bb
*/

return 0;
}

}

 

Another Example:

void function()
{
printf("Call function!\n");
}


int main(int argc, char* argv[])
{

void (*pf2)(); //pf2 is a pointer to a function that takes nothing and returns nothing.
void (*pf3)();
printf("pf2: %x\n&pf2: %x\n", (int)pf2, (int)&pf2);
*(int*)&pf2 = (int)function; //pf2 stores the address of function.
//*(int*)pf3 = (int)function; //Segmentation fault (core dumped). of course.
//pf3 = (int)&function; //worked, but incompatible type
pf3 = function; //worked. equivalent to "*(int*)&pf2 = (int)function;"
printf("function: %x\n&function: %x\n*function: %x\n", (int)function, (int)&function,*(int*)function);
printf("pf2: %x\n&pf2: %x\n", (int)pf2, (int)&pf2);
(*pf2)();
(*pf3)();
/* Output:
* pf2: b77a3270
* &pf2: bfb8a1d0
* function: 804851f //function = &function = *function
* &function: 804851f //function = &function = *function
* *function: 804851f //function = &function = *function
* pf2: 804851f
* &pf2: bfb8a1d0
* Call function!
* Call function!
*/

return 0;
}

 

(* (void (*)())0) (); //convert 0 to a function pointer. the function is stored at address beginning at 0. Then call the function

(* (char** (*)(char**,char**))0)(char**,char**);

 

*******函数指针数组 VS 函数指针数组的指针*******

char* (*pf[3])(char* p); //pf is the array name, not a pointer. the array contains three pointers to function.

 

char* (*(*pf)[3])(char* p); //pf is a pointer to an array of three pointers that point to functions.

char* fun1(char*p)
{
printf("fun1: %s\n", p);
return p;
}

char* fun2(char*p)
{
printf("fun2: %s\n", p);
return p;
}

char* fun3(char*p)
{
printf("fun3: %s\n", p);
return p;
}

int main()
{
char* (*fp1[3])(char*p);
char* (*(*fp2)[3])(char*p);
fp2 = &fp1;
fp1[0] = fun1;
fp1[1] = &fun2;
fp1[2] = &fun3;
fp2[0][0]("fp2[0][0]");
fp2[0][0]("fp2[0][1]");
fp2[0][0]("fp2[0][2]");
/* Output:
* fun1: fp2[0][0]
* fun1: fp2[0][1]
* fun1: fp2[0][2]
*/

return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值