1.字符串反转练习,给定一个字符串,让它反转输出,C语言版
include<stdio.h>
include<stdlib.h>
include<string.h>
int main()
{
char* source="script_wang";
int length=len(source);
char* des=(char*)malloc(length);//开辟一个内存空间
char* i=&source[length-1];//i指向字符串的最后一个字符
while(length!=0)
{
*des++=*i--;
length--;
}
*des=0;\\字符串的尾部以\0结尾
printf("%s",des);
free(des);\\释放
dest=NULL;\\防止产生野指针
}
//常见的错误写法
int main()
{
char a="hello";
char* str=&a;
strcpy(str,"hello");
printf(str);
return;
}
错误的原因在于:没有为 str 分配内存空间,将会发生异常
问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为
越界进行内在读写而导致程序崩溃。
Strcpy 的在库函数 string.h 中.程序的主要错误在于越界进行内存读写导致程序崩溃//
//正确的写法应该是
int main()
{
char* a="hello";//“hello”是字符串常量,所以a[0]='s'的赋值是不合法的
char* b=(char*)malloc(sizeof(a));
strcpy(b,a);
printf(b);
free(b);
b=NULL;\\防止产生野指针
}
/*
int a=3;
int *p;
p=&a;
*p=6;
printf("%d",*p);
int *b;
b=(int *)malloc(sizeof(int));
*b=5;
printf("%d",*b);
*/
为了能够理解指针,我也是煞费苦心,我的理解是:把指针*p当作是变量(知道是啥意思不?你怎么对待int buff;的就怎么对待他),而p当作是地址(认为是常量)。*为取值,&为取地址,然后你再去理解,是不是更容易一点呢?
上面的代码未经过测试!只是随便写一下。
说明:
char *src = "hello" 中的src是指向第一个字符‘h'的一个指针
char src[20] = "hello" 中数组名src也是执行数组第一个字符‘h’的指针
char a[]={ 'a ', 'b ', 'c '}; 'a ', 'b ', 'c ' 在栈里,可以去改变它 ,
char *a = "abc "; "abc "在静态存储区,不可以改变。
补充:
1.字符串的如何输入?
在C语言中没有字符串类型,用字符数组处理字符串
说明:
一维字符数组,用于存储和处理一个字符串 。二维字符数组,用于同时存储和处理多个字符串;
输入输出方法:逐个字符输入输出:%c 整个字符串输入输出:%s;
以字符串为单位处理时,直接使用数组名,无需&
输入字符串时,字符个数要小于数组的长度,例如输入5个字符,定义的字符数组至少应该有6个元素
输入字符串时,遇到回车或空格,输入结束,并且自动在串后面加上结束标志'\0'
输出字符串时,遇到字符串结束标志’\0',输出结束。
#include<stdio.h>
int main()
{
char ch[5];
scanf("%s", ch);
printf("%s", ch);//无需&
system("pause");
return 0;
}
用字符串处理函数输入和输出 在<string.h>头文件中
字符串输出函数puts
#include<string.h>
int main()
{
char str[10];
printf("请输入字符串");
gets(str);
printf("请输出字符串");
puts(str);
system("pause");
return 0;
}
参考:https://blog.csdn.net/baidu_37964044/article/details/79402046
2.若有 unsigned char *p1;
unsigned long *p2;
p1 = (unsigned char *)0x1000;
p2 = (unsigned long *)0x2000;
请问 p1+5=( ) p2+5=( )
答案:0x801005(相当于加上 5 位) 0x810014(相当于加上 20 位);
p1指向字符型,一次移动一个字符型,一次移动1个字节
p2指向长整型,一次移动一个长整型,一次移动4个字节
参考:https://blog.csdn.net/yuliu0552/article/details/6655452
3.进程和线程的差别。
答:线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于
进程的资源.
(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销
明显大于创建或撤消线程时的开销
其中:
首先只有在多线程中才有并发和并行的概念。
并行
并行是指两者同时执行,比如赛跑,两个人都在不停的往前跑;(资源够用,比如三个线程,四核的CPU )
并发
并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率。
区别:
并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
并发是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。
部分内容来自下面的简书,下面的内容还包括:线程安全
链接:https://www.jianshu.com/p/1200fd49b583
來源:简书
4.技术面面经
参考:http://www.sohu.com/a/234848072_690895
https://www.jianshu.com/p/60bb02e7c515
5.strlen与sizeof
sizeof函数是计算数据空间的字节数;
strlen函数是计算字符数组的字符数,以"\0"为结束判断,不包含结束字符'\0'。
总之,对于指针,sizeof操作符返回这个指针占的空间,一般是4个字节;而对于一个数组,sizeof返回这个数组所有元素占的总空间。
举例说明如下:
int a;
char b[]="abcd";
printf("%d", sizeof(a)); // 输出变量a所占的内存字节数,输出4
printf("%d", sizeof(b)); // 输出字符数组b所占的内存字节数,输出5(5=4+1,1为结束字符\0所占的内存)
printf("%d", strlen(b)); // 输出字符数组b中字符的个数,输出4(不含结束字符''\0)
char *str1="absde";
str1是一个指针,只是指向了字符串"absde"而已。所以sizeof(str1)不是字符串占的空间也不是字符数组占的空间,而是一个字符型指针占的空间。所以sizeof(str1)=sizeof(char*)=4,在C/C++中一个指针占4个字节
char str3[8]={'a',};
str3已经定义成了长度是8的数组,所以sizeof(str3)为8
参考:https://wenda.so.com/q/1387640751065741?src=9999&cid-pre=1000204
https://wenda.so.com/q/1371679689062635?src=150
5.static与extern
(1).修饰局部变量
(2).修饰全局变量
(3).修饰函数
改变函数的作用域
6.volate
7.列举几种进程的同步机制,并比较其优缺点。
答:原子操作
信号量机制
自旋锁
管程,会合,分布式系统
8.进程之间通信的途径
答 共享存储系统
消息传递系统
管道:以文件系统为基础
9.堆栈的区别
程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在
于( 堆)中。
Heap 是堆,stack 是栈。
Stack 的空间由操作系统自动分配/释放,Heap 上的空间手动分配/释放。
Stack 空间有限,Heap 是很大的自由存储区
C 中的 malloc 函数分配的内存空间即在堆上,C++中对应的是 new 操作符。
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传
递也在栈上进行
10、队列和栈有什么区别?
队列先进先出,栈后进先出
11.strcpy的原型函数
//将源字符串加 const,表明其为输入参数,加 2 分
char * strcpy( char *strDest, const char *strSrc )
{
//对源地址和目的地址加非 0 断言,加 3 分
assert( (strDest != NULL) && (strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0’ );
return address;
}
strlen的原型函数
assert( strt != NULL ); //断言字符串地址非0
int strlen( const char *str ) //输入参数const
{
assert( strt != NULL ); //断言字符串地址非0
int len;
while( (*str++) != '\0' )
{
len++;
}
return len;
}
12.注意:数组名作为函数参数时,退化为指针,一个指针为 4 个字节
void Func ( char str[100] )
{
sizeof( str ) = ?
}
sizeof( str ) = 4
13.构造函数的作用?并把构造函数的定义格式写出来
构造函数的作用:初始化对象的数据成员。
class Counter
{
public:
// 类Counter的构造函数
// 特点:以类名作为函数名,无返回类型
Counter()
{
m_value = 0;
}
private:
// 数据成员
int m_value;
}
该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作
eg: Counter c1;
编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter( )自动地初始化对象c1的m_value值设置为0。
深入了解的话:参考:https://www.cnblogs.com/zxouxuewei/p/5738272.html
14.谈谈对多态的理解
实现多态的三个条件:1)要有继承;2)要有虚函数重写;3)要有父类指针(引用)指向子类对象。
Java本来就是一种面向对象的语言,就是说任何事物都可以用java语言去描述。Java中的多态,目前在我看来,就是说,同一中事物可以有不同种的形态。所以当形容一个人(person)的时候,我们可以用老师(teacher)去形容他,也可以用父亲(father)去形容他,也可以用儿子(son)去形容他。这些就体现了事物的多面性,在java中我们就可以称之为多态。这里的person可以是一个基类,当然也可以是一个接口。而teacher,father,son都是person的子类或者说是实现类。Java的多态机制就是说父类可以引用子类的实例。而子类却不能引用父类的实例,原因很简单,父类的方法子类是一定有的而子类的方法父类却不一定有,子类引用父类实例之后,调用发方法父类就不一定存在了,所以子类是不能引用父类实例的。
参考:https://www.cnblogs.com/zxouxuewei/p/5738272.html
https://www.jb51.net/article/122036.htm
15.虚函数和纯虚函数的区别
参考:https://www.cnblogs.com/xudong-bupt/p/3570304.html
16.静态链接库和动态链接库的区别。
参考:https://blog.csdn.net/macmacip/article/details/54645927
如何拿到offer:博客链接:
https://blog.csdn.net/gengyiping18/article/details/38843893(只作参考,尽信书不如无书)