1.
#include <string.h>
int main(void)
{
char *str = "linux";
str[0] = "L";
char a;
char *t = &a;
strcpy(t, str);
printf("%s\n", t);
}
这个代码有两个问题,第一个其中并没有#include<stdio.h>头文件。第二个问题是他 str[0] = "L";这一行会出现一个报错,导致无法正常运行的,那么我可以对这一行进行删除,从而可以得到想要的linux这一行的字符
2.请将三维数组 arr 作为实参传递给 func() 并写出 func() 的函数定义。
请将三维数组 arr 作为实参传递给 func() 并写出 func() 的函数定义。当把这种三维数组的指针直接作为参数传递时,数组名退化为指针,函数并不知道数组的列数,N对它来说是不可见的,即使使用*(*(array +i) +j),第一层解引用失败。这时,编译器会报warning,运行生成的文件会发生segment fault。那么,为了指导这个函数如何解引用,也就是人为地解引用,需要把这个三维数组的首元素地址传给函数,于是就变成了下面的形式:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int func(int *array, int m, int n) {
int i,j;
for(i=0;i<m;i++) {
for(j=0;j<n;j++)
printf("\t%d", *(array +i*n +j));
printf("\n");
}
return 0;
}
int main(int argc,char** argv) {
int m=3,n=3,i;
int array[][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(*array,m,n);
return 0;
}
这是一个二维数组的情况但三维和他类似,在得到函数和数组将三维数组 arr 作为实参传递给 func() 并写出 func() 的函数定义。
3.
#include <stdio.h>
int main(void){
int a[10][5][3];
void* p=(void*)a;
int* pa=(int*)a;
long *p1=a;
char* p2=(char*)a;
int *t[4];
t[0]=(int*)&a[5];
t[1]=(int*)&a[1][1][0];
t[2]=t[0];
t[3]=(int*)&t[0]; printf("%p %p\n",a,t); printf("%p %p\n",(int(*)[4])t[1],*((int(*)[3][4])t[2]+1)+1); printf("%p %p\n",t[0]+1,&t[0]+1); printf("%p %p\n",*(&t[0]+1)+1,t[1]); printf("%p %p\n",t[3],t[3]-1);
return 0;
}
这个是该程序源代码在这里面,我认为在 long *p1=a; 这一行出现了问题, cannot convert 'int (*)[5][3]' to 'long int*' in initialization即无法在初始化时将“int(*)[5][3]”转换为“long int*”那么有两种方法对这里进行修改,第一种是对这里尚未进行的时候进行强制转化,使得其可以发生变化,第二种我认为更加简单,即对这一行进行删除即可。
#include <stdio.h>
int main(void){
&arr[0][0][0]; A
&arr[0][0][1]; A+1
&arr[0][1][0]; A=3
&arr[1][0][0]; A=15
&arr[0][1][1]; A=4
arr; A
**arr+1; A=3
*(*arr+1); A=15
**(arr+1); A+150
*(*arr+1)+1; A+18
*(*(arr+1))+1; A+153
&arr[0][2]+1; A+9
&arr[1]+1; A+30
&arr+1; A+150
pr1+2; A+2
pr2+2 A+8
pr3+2 A+16
pr4=2 A+8
}
t//B
t+1//B+8
t[0]+1//B+336
&t[0]+1//B+8
*(&t[0]+1)+1//B+252
t[1]//B+248
(int(*)[4])t[1]//B+248
((int(*)[4])t[1])+1//B+256
*((int(*)[3][4])t[2]+1)+1//B+396
t[3]//B
t[3]-1//B-4
4.查看二进制,
#include<iostream>
using namespace std;
int main()
{
int num,i=0,a[50];
cout<<"输入一个十进制整数"<<endl;
cin>>num;
while(num!=0)
{
a[i]=num%2;
num=num/2;
// cout<<a[i];
i++;
}
for(i=i-1;i>=0;i--)
{
cout<<a[i];
}
cout<<endl;
return 0;
}
5.通过宏函数交换两个 int 类型的变量
#include <stdio.h>
#define SWAP(T,m,n) {T s; s=m, m=n, n=s;}
int main()
{
short int i1,i2;
double d1,d2;
long l1,l2;
scanf("%hd%hd",&i1,&i2);
SWAP(short int,i1,i2);
printf("%hd %hd\n",i1,i2);
scanf("%lf%lf",&d1,&d2);
SWAP(double,d1,d2);
printf("%g %g\n",d1,d2);
scanf("%ld%ld",&l1,&l2);
SWAP(long,l1,l2);
printf("%ld %ld\n",l1,l2);
return 0;
}
6.结构体对齐
第一原则:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始
原则二:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。
举一个例子:
struct X
{
char a;
double b;
int c;
}S2;
比如说这个题是出来的char为1,double为8,int为4,这里面对齐之后的结果为24,参考以上的规则便很好得到
从源码到可执行文件这个题在19年的面试题中有描写,可以进行参考
7.括号匹配问题
1.扫描整个表达式;
2.判断当前字符是否为括号(左右括号)
①如果不是,则继续扫描下一个字符;
②如果是,则判断当前操作符是否为左括号
若为左括号—>直接入栈。
如果不是左括号,则说明是右括号,这时应该判断栈是否为空。
若栈为空—> 说明此表达式右括号多于左括号。
若栈不为空—>判断当前操作符是否和栈顶操作符匹配,若不匹配—->说明左右括号不匹配,若匹配—–>则继续判断下一个操作符。
3.最后,判断栈是否为空
①栈不为空—–>说明左括号多于右括号
②栈为空—–>说明括号匹配成功。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int match(char *str, int start, int end)
{
char chLeft;
char chRight;
while((start<=end) && (str[start] != '\0'))
{
switch(str[start])
{
case '(':
chLeft = str[start];
chRight = ')';
break;
case '[':
chLeft = str[start];
chRight = ']';
break;
case '{':
chLeft = str[start];
chRight = '}';
break;
case ')':
case ']':
case '}':
return 0;
default:
chLeft = '\0';
break;
}
if(str[start] == chLeft)
{
int a = 1;
int b=0;
int t = start+1;
while((t<=end) && (str[t] != '\0'))
{
if(str[t] == chLeft)
++a;
if(str[t] == chRight)
++b;
if(b>a)
return 0;
if(a == b)
{
if(0 == fun(str, start+1, t-1))
return 0;
start=t;
break;
}
++t;
}
if(a>b)
return 0;
}
++start;
}
return 1;
}
int main(void){
char str[1024];
gets(str);
int length = strlen(str);
int i = match(str, 0, length-1);
if(i == 1){
printf("括号匹配!\n");
}else{
printf("括号不匹配!\n");
}
return 0;
}
8.判断链表是否有环的存在
首先从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就从头节点重新遍历新节点之前的所有节点,用新节点ID和此节点之前所有节点ID依次作比较。如果发现新节点之前的所有节点当中存在相同节点ID,则说明该节点被遍历过两次,链表有环;如果之前的所有节点当中不存在相同的节点,就继续遍历下一个新节点,继续重复刚才的操作。
举一个例子
A->B->C->D->B->C->D, 当遍历到节点D的时候,我们需要比较的是之前的节点A、B、C,不存在相同节点。这时候要遍历的下一个新节点是B,B之前的节点A、B、C、D中恰好也存在B,因此B出现了两次,判断出链表有环。