C/C++指针、数组和引用

一、基本问题

(1)一元运算符&可用于取一个对象的地址

char  c;

p=&c;//p是指向c的指针

需要注意的是:地址运算符只能用于内存中的对象即变量与数组元素,他不能作用于表达式、常量式、register类型变量


(2)一元运算符*是间接引用运算符,它作用于指针时,将访问指针所指向的对象。

int x=1,y=2,z[10];

int *ip;//ip是指向int类型的指针

ip=&x;//ip指向x

y=*ip;//y的值现在为1

*ip=0;//x的值为0

ip=&z[0];//ip指向在z[0]

需要注意的是:每种指针必须指向某种特定的数据类型

y=*ip+1;//*ip指向的对象的值取出并加1

*ip+=1等价于++*ip等价于(*ip)++//ip指向对象的值加1

*ip++则表示将ip进行加1运算


(3)关于指针

需要注意的是:下面的几种是有效的指针运算

1.相同类型之间的赋值运算。指针也是变量,下面的操作是正确的

                             int *iq;

                             iq=ip;//将ip中的对象拷贝到iq中,这样iq也指向ip所指向的对象。

2.指针同整数之间的加减运算

3.如果指针p、q指向同一数组的成员,那么平p<q时,q-p+1就是位于p和q之间元素数目。

4.指针也可以初始化,只能是0或者地址表达式;指针与整数不能相互转化,但0是意外。

int * a =10;(错误写法,给指针赋值必须为地址,*p为所指向变量的值)

char * pstr="aslgkjklahjkla";

(4)数组与指针
1.举例说明他们的关系
int a[10];
int *pa;
pa=&a[0]=a;//pa的值是数组元素a[0]的地址 数组名代表数组最开始元素的地址
*(pa+i)=a[i]//true
f(&a[2])等价于f(a+2)
2.区别
指针是个变量,pa=a和pa++合法;
数组名不是变量,a=pa;a++非法;

(5)其他C/C++零散但笔试面试中需要注意的地方
1.‘1’是字符占一个字节,“1”是字符串占两个字节。
2.(int)(a+b)表示把a+b转型;(int)a+b表示把a转型再加b。
3.假设a=5,++a(是为6),a++(是为5),进行了++a和a++后下面的程序再用到a的话变量a值是6。
技巧:++在前先加后用,++在后先用后加
4.(2,3,4)的表达式数值就是4
逗号表达式的优先级别最低
5.char a=getchar()是没有参数的从键盘得到你输入的一个字符给变量a
  putchar('y')把字符y输出到屏幕中。
6.break和continue区别。
  break破了整个循环,看到break退出整个循环;
  continue继续循环运算,要结束本次循环,就是循环体内剩下的语句不再执行,跳到循环开始然后判断循环条件,进行新一轮循环。
举例说明:
#include<stdio.h>
int main()
{
char grade='C';
switch (grade)
{
case 'A':
case 'B':printf("good");
case 'C':
case 'D':printf("Pass");
default:
printf("error");
}
}
输出结果:Passerror
解析:如果case 'C'后添加break后输出空。
7.a=3!=2和(a=3)!=2 第一个a=1,第二个a=3
!=的级别高于=
8.关于二维数组需要注意的地方
a[3][3]={1,2,3,4,5,6,7,8,9};a是二维数组名它是行指针。
分析二维数组可以按下面考虑:

第一列第二列第三列
a[0]123第一行
a[1]456第二行
a[2]789第三行

*(a[0]+1)等价于a[0][1]
*(a[1]+2)等价于a[1][2]等价于*(a+1)[2]等价于再变成*(*(a+1)+2)第二行元素往后面跳二列


二、传递动态内存

1.下面5个函数哪个能够成功进行两个数的交换?
#include<iostream>
using namespace std;

void swap1(int p,int q)
{
int temp;
temp=p;
p=q;
q=temp;
}

void swap2(int *p,int *q)
{
int *temp;
*temp=*p//不是指向是拷贝 
*p=*q;
*q=*temp;
}

void swap3(int *p,int *q)
{
int *temp;
temp=p;
p=q;
q=temp;
}

void swap4(int *p,int *q)
{
int temp;
temp=*p;
*p=*q;
*q=temp;
}

void swap5(int &p,int &q)
{
int temp;
temp=p;
p=q;
q=temp;
}
int main()
{
int a=1,b=2;
//swap1(a,b);
//swap2(&a,&b);
//swap3(&a,&b);
//swap4(&a,&b);
//swap5(a,b);
cout<<a<<""<<b<<endl;
return 0;
}

答案:swap4函数和swap5函数

2.下面程序测试后会有什么结果?
#include<iostream>
void GetMemory(char *p,int num)
{
p=(char *)malloc(sizeof(char)*num);
};
int main()
{
char *str=NULL;
GetMemory(str,100);
strcpy(str,"hello");
return 0;
}

答案:程序崩溃。因为GetMemory并不能传递动态内存,Test函数的str一直都是NULL。
详细解释:p申请了新的内存,只是把p所指向的内存地址改变了,但是str丝毫未变。因为函数GetMemory没有返回值,因此str并不指向p所申请的那段内存。
拓展:改法(1)
#include<iostream>
void GetMemory(char **p,int num)
{
*p=(char *)malloc(sizeof(char)*num);//指针参数申请内存
};
int main()
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
cout<<*str<<endl;//输出h
cout<<str<<endl;//输出hello
cout<<&str<<endl;//输出0*22f7c
return 0;
}
拓展:改法(2)
#include<iostream>
void *GetMemory(char *p,int num)
{
p=(char *)malloc(sizeof(char)*num);
        return p;
};
int main()
{
char *str=NULL;
GetMemory(str,100);
strcpy(str,"hello");
return 0;
}


3.这个问题有什么问题?该如何修改?
char *strA()
{
char str[]="hello world";
return str;
}
答案:str存放的地址是函数栈"hello world"的首地址。因为这个函数返回的是局部变量的地址,当调用这个函数后,这个局部变量str就释放了,所以返回的结果是不确定的且不安全,随时都有被收回的可能。

改法1:const char* strA()
{
char *str="hello world";
return str;
}

改法2:const char* strA()
{
static char str[]="hello world";//static开辟一段静态存储空间。
return str;
}

4.下列程序会在哪一行崩溃?

struct S{

int i;

int * p;

};

main()

{

S s;

int *p=&s.i;//相当于int *p;    p=&s.i;

p[0]=4;

p[1]=3;

s.p=p;

s.p[1]=1;

s.p[0]=2;//崩溃

}

解析:当执行p[0]=4和p[1]=3的时候,p始终等于&s.i;

     s.p=p时s.p存了p的值也就是&s.i;那么s.p[1]=*(&s.i+1)即s.i的地址加1也就是s.p




三、函数指针

1.函数指针的基本了解(第二列为举例)
函数指针void (*f)()
函数返回指针void *f()
const指针const int*
指向const的指针

int* const;

指向const的const指针const int* const
int(*ptr)[]是一个指向整形数组的指针int *ptr[]和int *(ptr[])相同,指针数组,ptr[]里存的是地址。

接受任何类型参数并返回int类型参数int func(void *ptr)

2.关于函数指针比较难理解的几处
float(**def)[10]def是一个二级指针,指向的是一个一维数组的指针,数组的元素都是float
double *(*gh)[10]gh是一个指针,它指向的是一个一维数组,数组元素都是doubel*
double(*f[10])()f是一个数组,f有10个元素,元素都是函数的指针,指向的函数类型是没有参数且返回double的函数




四、指针数组和数组指针


1.以下程序的输出是?
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
int v[2][10]={{1,2,3,4,5,6,7,8,9,10},           {11,12,13,14,15,16,17,18,19,20}};
int (*a)[10]=v;//数组指针
cout<<**a<<endl;//输出1
cout<<**(a+1)<<endl;//输出11
cout<<*(*a+1)<<endl;//输出2
cout<<*(a[0]+1)<<endl;//输出2
cout<<*(a[1])<<endl;//输出11
}
需要注意的是:**a表示{1,2,3,4,5,6,7,8,9,10}
            **(a+1)表示{11,12,13,14,15,16,17,18,19,20}
            *(*a+1)表示2

2.下面程序输出结果是什么?
#include<iostream>
using namespace std;
main()
{
char* a[]={"hello","the","world"};
char**pa=a;
pa++;
cout<<*pa<<endl;
}
输出:the
解析:指针的指针的问题。


3.下面的操作会输出什么?为什么?

     
     
  1. #include<stdio.h> 
  2. int main(void
  3.     char *ptr = "Linux"
  4.     printf("\n [%c] \n",*ptr++); 
  5.     printf("\n [%c] \n",*ptr); 
  6.     return 0; 

答:输出结果应该是这样:

     
     
  1. [L]  
  2.  
  3. [i] 







待续未完……


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值