1.简述Makefile的作用
makefile文件和make工具一起使用,用于控制工程项目的编译和链接,也可以用来编写手册页和程序的安装。make工具用于解释执行makefile文件中的内容。makefile文件中通常包含源文件和目标文件的依赖关系以及从源文件生成目标文件的规则。make工具可以根据makefile判断哪些文件需要被重新编译,目标文件的构建顺序等。
2.sizeof与strlen的区别:
sizeof是算符,strlen是函数。
strlen 是返回字符串的长度。sizeof 是用来取得变量或类型所占用的内存大小的。
strlen测量的字符串长度要以‘\0’结尾,否则会一直找到有‘\0’为止。
3.什么是野指针?如何避免野指针。
野指针:指向不确定地址的指针变量。(即没有初始化)使用野指针易因内存泄露出现段错误。
内存泄露的原因:
1)访问了已经释放了的内存。
2)访问了没有权限的内存
避免野指针:在初始化的时候赋值,即使没有明确指定,也要赋NULL
eg:int *p = NULL;
4.c语言分配内存的方式有哪些?
c语言中常见的内存错误有哪些?
内存分配方式有三种:
1、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令集中,效率很高,凡是分配的内存容量有限。
2、从堆上分配。也称动态内存分配。程序在运行的时候用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或者delete释放内存。动态内存的生存期有程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收他。否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生堆内碎块。
3、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。
错误:
1)指针没有指向一块合法的内存
2)为地址分配的内存太小
3)内存分配成功,但并未初始化
4)内存越界
5)内存泄漏
6)内存已经释放,但是继续通过指针来使用
5.Static全局变量与普通变量的区别?
Static局部变量与普通局部变量的区别?
static函数与普通函数的区别?
static全局变量与普通全局变量的区别
static全局变量和普通全局变量的存储方式没有不同,如果它们都已经初始化,那么存放在进程的数据段中,否则存放在bss段。这两者的不同点在于作用域不同,当一个可执行目标文件是由多个源文件编译而成,则普通全局变量在在各个源文件都是有效的。而static全局变量只能在它定义的源文件中使用。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
static局部变量和普通局部变量的区别
static局部变量和普通局部变量的存储方式与作用域都不同。普通局部变量只在声明它的函数被调用时才会分配栈空间,并且只能在该函数内使用。而static局部变量存储在数据段或bss段中(静态存储区),并且源文件的所有函数都可以使用它。
static函数与普通函数的区别
static函数与普通函数的作用域不同。普通函数的定义和声明默认情况下是extern的,在源程序的所有文件中可见,但static函数只是在声明他的文件中可见,不能被其他文件所用。所以说定义static函数有以下好处:
1)其他文件中可以定义相同名字的函数,不会发生冲突
2)静态函数不能被其他文件所用。
6.#include <> 和 #include “” 有什么区别?
#include< > 引用的是编译器的类库路径里面的头文件。
#include" " 引用的是你程序目录的相对路径中的头文件。
7.char *const p; char const *p; const char *p 三者的区别。
char const *p;
一个指向const char 型的指针
*p不可以修改
p可以改写
char *const p;【p需要初始化】
p是指向int 的const指针,*p可以改写,p不可以
char const *const p
都不可以改写
8.写一个 宏MIN,这个宏输入两个参数并返回较小的一个。
另外,当你写下面代码时会发生什么事? least = MIN(*p++,b);
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
MIN(*p++, b)会产生宏的副作用,宏定义#define MIN(A,B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:((*p++) <= (b) ? (*p++) : (b)) 这个表达式会产生副作用,指针p会作两次++自增操作。
9.找出题中错误,并解释
void test1()
{
char string[10];
char* str1 = “0123456789”
strcpy(string, str1);
}
错误:char string[10]应该改成char string[11]。
因为字符串str1的长度应该包含‘\0’。长度应该是11。如果不改正会发生越界错误,,从而使其他变量的数据甚至程序代码被破坏
10.找出题中错误,并解释
void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory( str );
strcpy( str, “hello world” );
printf("%s", str);
}
错误:void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
GetMemory( str );
改成:
void GetMemory( char **p )
{
*p = (char *) malloc( 100 );
}
GetMemory( &str );
原因:改变形参指针的值并不会改变实参的值,一旦函数运行结束,形参p的内存会被释放掉,并不会返回给实参str,分配内存失败。把形参改为二级指针的话,改变形参的地址,就可以改变实参的值。内存分配成功。因为是二级指针,所以GetMemory( &str );的实参应该是str的地址。
11: 输入一段字符串,无论是否有重复字母出现,都只打印出现过的小写字母,并按照小写字母顺序打印。
(如输入qewqwr322rqw<>211qESFSSEraZz, 打印aeqrwz)
#include <stdio.h>
#include <stdlib.h>
#define N 500
int main()
{
char str1[N] = {0};
char str2[N] = {0};
int i;
int index = 0;
scanf("%s",str1);
for(i = 0; *(str1 + i) != '\0'; i++)
{
index = *(str1 + i) - 97;
*(str2 + index + 97) = '+'; //+为标记
}
for(i = 97; i < 26 + 97; i++)
{
if(*(str2 +i) == '+')
{
printf("%c",i);
}
}
printf("\n");
return 0;
}
12:输入某个月的第N周和这一周的第M天,通过int *GetDay() 函数获取参数并返回结果,来得出这一天是这个月的第多少天。
(如输入:3,4,即这个月的第3周的第4天,即这个月的第18天)
#include <stdio.h>
int GetDay(int day,int week)
{
int date;
date = (week - 1) * 7 + day;
return date;
}
int main()
{
int day,week;
int date;
printf("请输入第几周第几天\n");
scanf("%d%d",&week,&day);
date = GetDay(day,week);
printf("这是这个月的第%d天\n",date);
return 0;
}
13:(1)建立一个顺序表,要求从键盘输入10个整数,并将该顺序表的元素从屏幕显示出来。
(2)用函数实现在顺序表中查找其中一个元素,如果找到,返回该元素在顺序表中的位置和该元素的值,否则提示无此元素。
(3)用函数实现顺序表的插入和删除操作。由用户输入待插入元素及插入位置,将完成插入后的顺序表输出;由用户输入删除第几个元素,将完成删除后的顺序表输出。
#include <stdio.h>
#include <stdlib.h>
struct node
{
int num;
struct node * next;
};
typedef struct node Node;
typedef struct node * Link;
void create_link(Link * head)
{
*head = NULL;
}
void insert_node_tail(Link *head,Link new_node)
{
Link p;
p = *head;
if(p == NULL)
{
*head = new_node;
new_node->next = NULL;
}
else
{
while(p->next != NULL)
{
p = p->next;
}
p->next = new_node;
new_node->next = NULL;
}
}
void malloc_ok(Link new_node)
{
if(new_node == NULL)
{
printf("malloc error.\n");
exit(-1);
}
}
void create_node(Link * new_node, int i)
{
(*new_node) = (Link)malloc(sizeof(Node));
malloc_ok(*new_node);
(*new_node)->num = i;
}
void insert_node_mid(Link * head,Link new_node,int num_loc)
{
Link p,q;
p = *head;
q = NULL;
if(p == NULL)
{
*head = new_node;
new_node->next = NULL;
}
else
{
while(p->num != num_loc && p->next != NULL)
{
p = p->next;
}
}
if(p->next == NULL && p->num != num_loc)
{
p->next = new_node;
new_node->next = NULL;
}
else
{
q = p->next;
p->next = new_node;
new_node->next = q;
}
}
void node_del(Link * head, int num_val)
{
Link p,q;
p = q = *head;
int i;
if(p == NULL)
{
printf("链表为空!\n");
}
else
{
for(i = 1;i < num_val; i++)
{
q = p;
p = p->next;
}
if((*head)->num == num_val)
{
*head = (*head)->next;
free(p);
}
else if(p->next == NULL && p->num != num_val)
{
printf("没有找到数。\n");
}
else
{
q->next = p->next;
free(p);
}
}
}
void display(Link head)
{
Link p;
p = head;
while(p != NULL)
{
printf("num = %d\n",p->num);
p = p->next;
}
}
int main()
{
int i,j;
int num[10];
Link head = NULL;
Link new_node = NULL;
int num_val,num_loc;
printf("请输入10个整数。\n");
for(i = 0; i < 10; i++)
{
scanf("%d",&num[i]);
}
create_link(&head);
for(i = 0; i < 10; i++)
{
create_node(&new_node,num[i]);
insert_node_tail(&head,new_node);
}
printf("请输入要插入的位置。\n");
scanf("%d",&num_loc);
printf("请输入要插入的数。\n");
scanf("%d",&num_val);
create_node(&new_node,num_val);
insert_node_mid(&head,new_node,num_loc);
display(head);
printf("请输入要删除的数的位置是第几个。\n");
scanf("%d",&num_val);
node_del(&head,num_val);
display(head);
return 0;
}