linux c第四天———gcc、gdb、指针、大小端存储

1、gcc的编译流程
在这里插入图片描述

1、预处理
处理所有以#开头的指令,比如#include #define #ifdef。。。。。
进行了符号替换
gcc -E 1.c -o 1.i

2、编译
检查有无语法错误,如果没有语法错误,就编译为汇编代码,如果有语法错误,就报错
gcc -S 1.c -o 1.s

3、汇编
将汇编代码变成二进制代码
gcc -c 1.c -o 1.o

4、链接
一个工程中有很多.c文件,前面三步完成之后所有的.c都会变成.o,链接就是将所有的.o合并成一个可执行的二进制文件

动态链接:在编译阶段不会将库加入到a.out中,而是在运行阶段才会去到/lib目录找对应的库,生成的a.out比较小
静态链接:在编译阶段就将库加入到a.out中,所以最终生成的a.out就会比较大

2、gdb调试
gcc 1.c -g
gdb a.out
r
b
p
n
s

段错误:非法操作内存
哪些情况会出现段错误呢?
1、操作了空指针
2、操作了野指针
3、数组越界
3、指针
指针:内存的基本单元是字节,每一个字节都有一个编号,这个编号就称为地址

指针变量:专门用来存放地址的变量

也就是说:指针变量的内存空间里存的是内存单元的编号,那也就意味着通过指针可以找到这块内存空间,进而能够访问这块空间

指针的本质:操作内存的工具

注意:不管是什么类型的指针,所占内存空间的大小是一样的,如果是32位的系统就是4字节,如果是64位的系统就是8字节

定义:数据类型 *p = &a;
p的类型:数据类型 *
指针所指向的类型:数据类型,决定了指针变量一次能够操作的内存空间的大小
如果是int,就一次访问四个字节,如果是char就一次访问一个字节

注意:指针是操作内存的利器,非常的好用,但是也很危险

所以:在操作内存,要注意不能越界,必须操作的是一块有效的内存

二级指针:存放的是一级指针的地址
数组指针:指向整个一维数组的指针,+1移动一个一维数组的大小
int (*p)[3];
指针数组:数组元素是指针的数组
int *p[3];
函数指针:指向函数的指针,就是这个指针存放的是函数的入口地址,因为函数本质是一段二进制代码,这段代码的首地址就是函数的入口地址,函数名就是函数的入口地址

int (*p)();

如何看一个指针的类型?
先找到指针变量,先往右看,再往左看,先和谁结合就是什么,遇到小括号就被挡住,那就先看反方向

void (*signal(int signum, void (*handler)(int)))(int);

typedef void (AA*)(int);
AA signal(int no, AA handler);

回调函数:通过调用一个函数触发调用另外一个函数
实现:函数指针作为函数的形参,然后通过这个函数指针来调用函数,就叫函数回调
在这里插入图片描述

面试题10:看代码写结果----用指针赋值
考点:用指针赋值
出现频率:****

int main()
{
char a[] = “hello, world”;
char *ptr = a;
printf("%c\n", *(ptr+4));
printf("%c\n", ptr[4]);
printf("%c\n", a[4]);
printf("%c\n", *(a+4));

*(ptr+4) += 1;
printf("%s\n", a);

return 0;
}

int main()
{
int a[5] = {1,2,3,4,5};
int *ptr = (int *)(&a+1);

printf("%d\n", *(a+1));
printf("%d\n", *(ptr-1));

return 0;
}

面试题12 指针比较
写出下面程序的结果
考点:指针比较操作

int main()
{
char str1[] = “abc”;
char str2[] = “abc”;
const char str3[] = “abc”;
const char str4[] = “abc”;
const char *str5 = “abc”;
const char *str6 = “abc”;
char *str7 = “abc”;
char *str8 = “abc”;

cout << (str1 == str2) << endl;
cout << (str3 == str4) << endl;
cout << (str5 == str6) << endl;
cout << (str6 == str7) << endl;
cout << (str7 == str8) << endl;
return 0;
}

面试题13:看代码找错误-----内存访问违规
考点:指针操作内存违规
出现频率:****

int main()
{
char a;
char *str1 = &a;
char *str2 = “AAA”;
strcpy(str1, “hello”);
cout << str1 << endl;

str2[0] = ‘B’;
cout << str2 << endl;

return 0;
}

面试题14:指针的隐式转换
找出下面代码中的错误
考点:指针类型的隐式转换
出现频率:****

int main() 3
{
int ival = 1024;
int ival2 = 2048;
int *pi1 = &ival;
int *pi2 = &ival2;
int **pi3 = 0;

ival = *pi3; 11
*pi2 = *pi3;
ival = pi2;
pi2 = *pi1;
pi1 = *pi3;
ival = *pi1;
pi1 = ival;
pi3 = &pi2;
return 0;
}

面试题15:指针常量与常量指针的区别
考点:指针常量与常量指针的区别
出现频率:*****

答案:
常量指针就是指向常量的指针,它所指向的地址的内容是不可修改的
指针常量就是指针的常量,它是不可改变地址的指针,但是可以对它所指向的内容进行修改

面试题16 指针的区别
考点:const关键字在指针声明时的作用
出现频率:*****

下述4个指针有什么区别?
char *const p1;
char const *p2;
const char *p3;
const char *const p4;

面试题17:找错—常量指针和指针常量的作用
考点:常量指针和指针常量的作用
出现频率:****

int main()
{
const char *node1 = “abc”;
char *const node2 = “abc”;

node1[2] = ‘k’; 8
*node1[2] = ‘k’; 9
*node1 = “xyz”; 10
node1 = “xyz”; 11

node2[2] = ‘k’; 13
*node2[2] = ‘k’;
*node2= “xyz”;
node2 = “xyz”;
return 0;
}

面试题21:找错—指针数组和数组指针的使用
考点:指针数组和数组指针的使用
出现频率:****

int main()
{
char *str[] = {“Welcome”, “to”, “Fortemedia”, “Nanjing”};
char **p = str + 1;
str[0] = (*p++) + 2;
str[1] = *(p+1);
str[2] = p[1] + 3;
str[3] = p[0] + (str[2] - str[1]);
printf("%s\n", str[0]);
printf("%s\n", str[1]);
printf("%s\n", str[2]);
printf("%s\n", str[3]);
return 0;
}

面试题22:函数指针和指针函数的区别
考点:函数指针和指针函数的区别
出现频率:*****

答案:指针函数是返回值为指针的函数
函数指针是指向函数的指针

面试题23:数组指针与函数指针的定义
考点:数组指针与函数指针的定义
出现频率:***

定义下面的几种类型变量:
a、含有10个元素的指针数组
b、数组指针
c、函数指针
d、指向函数的指针数组

面试题25:代码改错----函数指针的使用
考点:函数指针的使用
下面的程序有什么问题?它打印出三个数的最大者
int max(int x, int y)
{
return x > y ? x : y;
}

int main()
{
int *p;
int a, b, c;
int result;
int max(x, y);

p = max;
cout << “please input three integer” << endl;
cin >> a >> b >> c;
result = (*p)((*p)(a, b), c);
cout << "result = " << result << endl;
return 0;
}

面试题26:看代码写结果-----函数指针的使用
考点:函数指针的使用
出现频率:****

int add1(int a1, int b1);
int add2(int a2, int b2);
int main()
{
int numa1 = 1, numb1 = 2;
int numa2 = 2, numb2 = 3;
int (*op[2])(int a, int b);
op[0] = add1;
op[1] = add2;
printf("%d %d\n", op[0](numa1, numb1), op[1](numa2, numb2));
getchar();
return 0;
}

int add1(int a1, int b1)
{
return a1 + b1;
}
int add2(int a2, int b2)
{
return a2 + b2;
}

面试题27:typedef用于函数指针的定义
考点:函数指针定义中typedef的作用
出现频率:***

下面的定义有什么作用?
typedef int (*pfun)(int x, int y);

面试题35:比较分析两个代码段的输出—动态内存的传递
考点:动态内存的传递
出现频率:*****

程序1:
char *GetMemory()
{
char p[] = “hello world!”;
return p;
}

void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}

程序2:
void GetMemory(cagr *p)
{
p = (char *)malloc(100);
}

vois Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, “hello world”);
printf(str);
}

4、大小端
大端存储:将低字节数据存放在高地址,将高字节数据存放在低地址
小端存储:将低字节数据存放在低地址,将高字节数据存放在高地址

注意:怎么存的,就怎么取的

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值