程序题
c语言,使用fgets和fputs计算行数,并拷贝文件。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, const char *argv[])
{
FILE *p1;
FILE *p2;
if((p1 = fopen("./fopen.txt", "r")) == NULL)
{
perror("fopen error");
return -1;
}
if((p2 = fopen("./fopen1.txt", "w")) == NULL)
{
perror("fopen error");
return -2;
}
char c[2] = {0};
int count = 0;
while(fgets(c, sizeof(c), p1) != NULL)
{
fputs(c, p2);
int tail = strlen(c) - 1;
if(c[tail] == '\n')
count++;
}
printf("行数为%d\n", count);
fclose(p1);
fclose(p2);
return 0;
}
面试题
1. 快速排序算法的思想
快速排序是一种常用的排序算法,其基本思想是通过分治的思想将一个大问题分解为多个小问题来解决。
具体步骤如下:
- 选择一个基准元素(pivot),可以是数组中的任意一个元素。
- 将数组分成两部分,左边部分的元素都小于等于基准元素,右边部分的元素都大于等于基准元素。
- 对左右两部分分别进行快速排序,即递归地调用快速排序算法。
- 合并左右两部分的结果,即得到最终排序结果。
具体的实现过程如下:
- 设定两个指针i和j,分别指向数组的起始位置和结束位置。
- 从数组的末尾开始,找到一个小于基准元素的元素,将其与指针i指向的元素交换位置。
- 从数组的起始位置开始,找到一个大于基准元素的元素,将其与指针j指向的元素交换位置。
- 重复步骤2和步骤3,直到i和j指针相遇。
- 将基准元素与相遇位置的元素交换位置,此时基准元素左边的元素都小于等于基准元素,右边的元素都大于等于基准元素。
- 对基准元素左右两部分分别进行快速排序,即递归地调用快速排序算法。
快速排序的时间复杂度为O(nlogn),其中n为数组的长度。快速排序是一种原地排序算法,不需要额外的空间。但是在最坏情况下,快速排序的时间复杂度可能达到O(n^2),即数组已经有序或者基本有序的情况下。为了避免最坏情况的发生,可以采用随机选择基准元素的方式来提高快速排序的性能。
2. 数组和链表的区别(逻辑结构,内存存储,访问方式三个方面辨析)
数组和链表是两种常见的数据结构,它们在逻辑结构、内存存储和访问方式上存在一些区别。
-
逻辑结构: 数组是一种线性结构,元素在内存中是连续存储的,通过索引可以直接访问任意位置的元素。数组的元素顺序是固定的,插入和删除元素需要移动其他元素。 链表也是一种线性结构,元素在内存中可以是离散存储的,每个元素包含一个指向下一个元素的指针。链表的元素顺序是可变的,插入和删除元素只需要改变指针的指向。
-
内存存储: 数组的元素在内存中是连续存储的,占用的内存空间是固定的。当数组需要扩容时,需要重新分配一块更大的连续内存空间,并将原数组的元素复制到新的内存空间中。 链表的元素在内存中可以是离散存储的,每个元素包含一个指向下一个元素的指针。链表的内存空间是动态分配的,每个元素可以单独存储在任意位置,不需要连续的内存空间。
-
访问方式: 数组通过索引直接访问元素,可以在O(1)的时间复杂度内完成。但是插入和删除元素时,需要移动其他元素,平均时间复杂度为O(n)。 链表需要从头节点开始依次遍历,找到目标位置的元素,平均时间复杂度为O(n)。但是插入和删除元素时,只需要改变指针的指向,平均时间复杂度为O(1)。
综上所述,数组适合随机访问,但插入和删除元素的效率较低;链表适合插入和删除元素,但访问元素的效率较低。在实际应用中,根据具体的需求选择适合的数据结构。
3. 赋值与初始化的区别
赋值是将一个值或表达式赋给一个已存在的变量或数据结构,用于更新其值;初始化是在创建变量或数据结构时为其赋予初始值,用于确保变量在使用之前具有已知的初始值。赋值可以在变量已经存在的情况下进行,而初始化必须在变量定义时进行。
4. 结构体和共用体的区别
区别:
- 结构体的成员变量占用独立的内存空间,它们可以同时存在并独立访问;共用体的成员变量共享同一块内存空间,同一时间只能访问其中一个成员变量。
- 结构体的大小取决于其成员变量的类型和顺序;共用体的大小取决于其最大成员变量的大小。
- 结构体的成员变量可以同时存储和访问不同的数据;共用体的成员变量只能存储和访问同一块内存空间中的数据。
- 结构体的成员变量可以具有不同的数据类型;共用体的成员变量必须具有相同的数据类型。
结构体和共用体在不同的场景下有不同的应用。结构体适用于需要组织和管理多个不同类型的数据的情况;共用体适用于需要共享内存空间来存储不同类型的数据的情况。
5. 形参和实参有什么区别
形参是函数定义中的参数,用于声明函数接受的参数的类型和名称;实参是函数调用时传递给函数的参数的值或表达式。形参在函数定义时起到占位符的作用,用于接收实参的值并在函数体内使用;实参提供具体的数据,供函数在执行时使用。形参和实参之间是一种对应关系,必须满足类型匹配的要求。
6. void指针就是空指针吗?他有什么作用?
不,void指针并不是空指针。空指针是指未指向任何有效内存地址的指针,而void指针是一种特殊类型的指针,它可以指向任何类型的数据,但不能直接进行解引用操作。
void指针的作用是提供一种通用的指针类型,可以用来存储任意类型的指针,而不需要指定具体的类型。在某些情况下,我们可能无法确定指针所指向的数据的具体类型,或者需要在不同类型之间进行指针转换,这时可以使用void指针来处理这些情况。
具体来说,void指针可以用于以下几种情况:
-
作为函数的参数或返回值:当函数需要接受或返回不同类型的指针时,可以使用void指针作为参数或返回值类型。这样可以增加函数的通用性和灵活性。
-
作为动态内存分配的返回值:当使用动态内存分配函数(如malloc)分配内存时,返回的指针类型是void指针。在使用之前,需要将void指针转换为特定类型的指针。
-
作为指针的通用类型:当需要存储不同类型的指针时,可以使用void指针来实现通用的指针类型。但是,在使用时需要注意将void指针转换为特定类型的指针,以确保正确访问和操作数据。
需要注意的是,使用void指针时需要谨慎操作,因为void指针无法直接进行解引用操作,必须在使用前将其转换为具体类型的指针。在转换时需要确保指针的类型匹配,否则可能导致类型错误和未定义行为。