《Linux C编程实战》笔记:实现自己的ls命令

news2024/12/24 10:19:13

关键函数的功能及说明

1.void display_attribute(struct stat buf,char *name)

函数功能:打印文件名为name的文件信息,如

含义分别为:文件的类型和访问权限,文件的链接数,文件的所有者,文件所有者所属的组,文件大小,文件创建的时间

2.void dispaly_single(char *name)

函数功能:输出文件的文件名,如果命令中没有-l选项,则输出文件名时要保证上下对齐,如:

3.void display(int flag,char *pathname)

函数功能:根据命令行参数(存放在flag中)和完整路径名(存放在pathname中)显示目标文件,参数flag可以取以下值或者它们的组合

4.void diaplay_dir(int flag_param,char *path)

函数功能:为显示某个目录下的文件做准备,参数flag_param用于在调用display函数时作为其参数flag的实参,path是要显示的目录

函数流程

准备工作代码:

#include<cstdlib>
#include<cstring>
#include <cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
#include<dirent.h>
#include<linux/limits.h>
#include<pwd.h>
#include<grp.h>
#include<algorithm>
using namespace std;

#define PARAM_NONE 0//无参数
#define PARAM_A 1//-a 显示所有文件
#define PARAM_L 2  //-l 一行只显示一个文件的详细信息
#define MAXROWLEN 80    //一行显示的最多字符数

int g_leave_len=MAXROWLEN;//一行剩余长度,用于输出对齐
int g_maxlen;             //存放某目录下最长文件名的长度
//自定义错误处理函数
void my_err(const char *err_string,int line){
    fprintf(stderr,"line:%d ",line);
    perror(err_string);
    exit(1);
}
int cmp(const void *a, const void *b)
{
    return ((char *)a)[0] - ((char *)b)[0];
}

顺便了解

pwd.hgrp.h 是两个C语言标准库头文件,用于处理用户和组的信息,通常用于UNIX和类UNIX系统。

  1. pwd.h - Password Database:

    该头文件定义了与用户账户信息相关的结构和函数。主要包括获取和处理用户账户信息的功能,例如用户名、用户ID(UID)、组ID(GID)、用户家目录等。一些常见的函数和结构体包括:
    • getpwnam:通过用户名获取用户信息。
    • getpwuid:通过用户ID获取用户信息。
    • struct passwd:用于存储用户账户信息的结构体。
  2. grp.h - Group Database:

    该头文件定义了与用户组信息相关的结构和函数。主要包括获取和处理用户组信息的功能,例如组名、组ID(GID)、组成员等。一些常见的函数和结构体包括:
    • struct group:用于存储用户组信息的结构体。
    • getgrgid:通过组ID获取组信息。
    • getgrnam:通过组名获取组信息。

如果你不清楚函数代码实在干嘛,可以看一下上面的运行结果,这样才知道到底要输出什么

display_attribute代码:

//获取文件属性并打印
void display_attribute(struct stat buf,char *name){
    char buf_time[32];
    struct passwd *psd;//从该结构体中获取文件所有者的用户名
    struct group *grp;//从该结构体中获取文件所有者所属组的组名
    //获取并打印文件类型
    if(S_ISLNK(buf.st_mode))
        printf("l");//符号链接
    else if(S_ISREG(buf.st_mode))
        printf("-");//普通文件
    else if(S_ISDIR(buf.st_mode))
        printf("d");//目录
    else if(S_ISCHR(buf.st_mode))
        printf("c");//字符设备文件
    else if(S_ISBLK(buf.st_mode))
        printf("b");//块设配文件
    else if(S_ISSOCK(buf.st_mode))
        printf("s");//套接字文件
    else if(S_ISFIFO(buf.st_mode))
        printf("f");//FIFO文件

    //获取并打印文件所有者的权限
    if(buf.st_mode&S_IRUSR)
        printf("r");
    else printf("-");
    if(buf.st_mode&S_IWUSR)
        printf("w");
    else printf("-");
    if(buf.st_mode&S_IXUSR)
        printf("x");
    else printf("-");

    //获取并打印与文件所有者同组的用户对该文件的操作权限
    if(buf.st_mode&S_IRGRP)
        printf("r");
    else printf("-");
    if(buf.st_mode&S_IWGRP)
        printf("w");
    else printf("-");
    if(buf.st_mode&S_IXGRP)
        printf("x");
    else printf("-");

    //获取并打印其他用户对该文件的操作权限
    if(buf.st_mode&S_IROTH)
        printf("r");
    else printf("-");
    if(buf.st_mode&S_IWOTH)
        printf("w");
    else printf("-");
    if(buf.st_mode&S_IXOTH)
        printf("x");
    else printf("-");

    printf("   ");
    
    //根据uid与gid获取文件所有者的用户名与组名
    psd=getpwuid(buf.st_uid);
    grp=getgrgid(buf.st_gid);
    printf("%4d",buf.st_nlink);//打印文件的链接数
    printf("%-8s",psd->pw_name);
    printf("%-8s",grp->gr_name);

    printf("%6d",buf.st_size);//打印文件的大小
    strcpy(buf_time,ctime(&buf.st_mtime));
    buf_time[strlen(buf_time)-1]='\0';//去掉换行符
    printf("  %s",buf_time);//打印文件的时间信息
}

struct stat这个结构体在《Linux C编程实战》笔记:文件属性操作函数-CSDN博客 这里放过具体的信息,可以看到主要是从st_mode获取信息

S_ISLNK 是一个宏(macro),通常用于检查给定文件的模式是否表示一个符号链接(Symbolic Link)。这个宏在UNIX和类UNIX系统的系统编程中很常见,特别是在处理文件和目录时。

S_ISLNK 的定义通常在 <sys/stat.h> 头文件中,这个头文件包含了有关文件状态(file status)的相关宏和结构体定义。它的典型用法是与 st_mode 结构成员一起使用

其他的宏都是类似的作用,用来检查文件具体是那种类型的。

buf.st_mode & S_IRGRP 是一个位运算的操作,用于检查给定文件的权限位

S_IRGRP之类的文件权限的宏在 《Linux C编程实战》笔记:文件读写-CSDN博客 有具体解释过,通过这个操作可以得知文件的具体权限

getpwuidgetgrgid 函数来获取文件或目录的所有者(user)和所属组(group)的相关信息。这两个函数通常与文件状态结构 struct stat 中的 st_uid(用户ID)和 st_gid(组ID)成员一起使用。

#include <pwd.h>

struct passwd *getpwuid(uid_t uid);
#include <grp.h>

struct group *getgrgid(gid_t gid);
struct passwd {
    char   *pw_name;       // 用户名
    char   *pw_passwd;     // 加密后的密码
    uid_t   pw_uid;        // 用户ID
    gid_t   pw_gid;        // 主组ID
    char   *pw_gecos;      // 用户的真实姓名等描述信息
    char   *pw_dir;        // 用户的主目录
    char   *pw_shell;      // 用户的登录shell
};
struct group {
    char   *gr_name;       // 组名
    char   *gr_passwd;     // 加密后的密码(在 /etc/gshadow 中)
    gid_t   gr_gid;        // 组ID
    char  **gr_mem;        // 用户名的数组,表示属于这个组的成员
};

ctime的具体用法也在 《Linux C编程实战》笔记:文件属性操作函数-CSDN博客 有提到

%-8s的格式时,它包含两个部分:-8 是一个标志(flag),表示左对齐输出,而 %s 表示将一个字符串插入到该位置。

  • %s:插入一个字符串。
  • -8:左对齐,并占用最少8个字符的宽度。如果字符串长度不足8个字符,将用空格在右侧填充。

dispaly_single代码:

//在没有使用-l选项时,打印一个文件名,打印时上下对齐
void display_single(char *name){
    int i,len;
    //如果本行不足以打印一个文件名则换行
    if(g_leave_len<g_maxlen){
        printf("\n");
        g_leave_len=MAXROWLEN;
    }
    len=strlen(name);
    len=g_maxlen-len;
    printf("%-s",name);
    //为了保持对齐,需要填充空格来实现和最长文件名占位相同
    for(i=0;i<len;i++){
        printf(" ");
    }
    printf("  ");
    g_leave_len-=(g_maxlen+2);//改行剩下的长度减去最长文件名加两个空格的长度
}

这里主要是格式控制,在准备代码里有每个变量具体的含义,每次输出主要是更新g_leave_len

display代码:

/*
*    根据命令行参数和完整路径名显示目标文件
*    参数flag:命令行参数
*    参数pathname:包含了文件名的路径名
*/
void display(int flag,char *pathname){
    int i,j;
    struct stat buf;
    char name[NAME_MAX+1];
    //从路径中解析出文件名,其实就是最后一个/后面的字符串了
    //书中代码是这么来获得的,感觉应该有更好的方法(C语言好像没有split函数,多少会麻烦一些)
    for(i=0,j=0;i<strlen(pathname);i++){
        if(pathname[i]=='/'){
            j=0;
            continue;
        }
        name[j++]=pathname[i];
    }
    name[j]='\0';
    //用lstat而不是stat以方便解析链接文件
    if(lstat(pathname,&buf)==-1)
        my_err("stat",__LINE__);
    switch (flag)
    {
    case PARAM_NONE://没有选项
        if(name[0]!='.'){//隐藏的.目录文件就忽略
            display_single(name);
        }
        break;
    case PARAM_A:
        display_single(name);
        break;
    case PARAM_L:
        if(name[0]!='.'){
            display_attribute(buf,name);//详细信息
            printf(" %s-\n",name);//最后打印文件名
        }
        break;
    case PARAM_A+PARAM_L:
        display_attribute(buf,name);
        printf(" %-s\n",name);
        break;
    default:
        break;
    }
}

NAME_MAX在《Linux C编程实战》笔记:目录操作-CSDN博客

lstat在《Linux C编程实战》笔记:文件属性操作函数-CSDN博客

display_dir代码:

void display_dir(int flag_param,char *path){
    DIR *dir;
    struct dirent *ptr;
    int count=0;
    char filenames[256][PATH_MAX+1],temp[PATH_MAX+1];
    //获取该目录下文件总数和最长的文件名
    dir=opendir(path);
    if(dir==nullptr)
        my_err("opendir",__LINE__);
    while((ptr=readdir(dir))!=nullptr){
        if(g_maxlen<strlen(ptr->d_name))
            g_maxlen=strlen(ptr->d_name);//更新最长的文件名长度
        count++;
    }
    closedir(dir);

    if (count>256)
    {
        my_err("too maney files under this dir",__LINE__);
    }
    int i,j,len=strlen(path);
    //获取该目录下所有的文件名
    dir=opendir(path);
    for(i=0;i<count;i++){
        ptr=readdir(dir);
        if(ptr==nullptr)
            my_err("readdir",__LINE__);
        strncpy(filenames[i],path,len);
        filenames[i][len]='\0';
        strcat(filenames[i],ptr->d_name);//把目录名称和目录下的文件名拼一起
        filenames[i][len+strlen(ptr->d_name)]='\0';
    }
    //给文件名排序
    //源代码里用的是冒泡,排序不是重点,用一下stl算了,偷个懒
    qsort(filenames,count,sizeof(filenames[0]),cmp);
    for(i=0;i<count;i++)
        display(flag_param,filenames[i]);
    closedir(dir);
    //如果命令行中没有-l选项,打印一个换行符
    if((flag_param&PARAM_L)==0)
        printf("\n");
}

打开目录和遍历目录的操作我已经演示过了了《Linux C编程实战》笔记:目录操作-CSDN博客

main函数代码:

int main(int argc,char **argv){
    int i,j,k,num;
    char path[PATH_MAX+1];
    char param[32];//保存命令行参数,目标文件名和目录名不在这里
    int flag_param=PARAM_NONE;//参数种类
    struct stat buf;
    //命令行参数的解析,分析 -l、-a、-al、-la选项
    j=0;
    num=0;
    for(i=1;i<argc;i++){
        if(argv[i][0]=='-'){//是一个命令
            for(k=1;k<strlen(argv[i]);k++,j++){
                param[j]=argv[i][k];//把命令的参数(a或l)都放到param数组里
            }
        num++;//保存"-"的个数
        }
    }
    //j现在是param数组的长度
    for(int i=0;i<j;i++){//遍历param数组,看参数都是什么
        if(param[i]=='a'){
            flag_param|=PARAM_A;
            continue;
        }
        else if(param[i]=='l'){
            flag_param|=PARAM_L;
            continue;
        }else{//a,l以外的参数,不支持
            printf("my_ls:invalid option -%c\n",param[i]);
            exit(1);
        }
    }
    param[j]='\0';
    //如果没有输入文件名或目录则显示当前目录
    if((num+1)==argc){//这表示除了参数,没有输入文件或目录
        strcpy(path,"./");//path变成当前目录
        path[2]='\0';
        display_dir(flag_param,path);//用显示目录的函数
        return 0;
    }
    //开始遍历文件或目录
    i=1;
    do
    {
        //如果不是目标文件或目录,解析下一个命令行参数
        if(argv[i][0]=='-'){
            i++;
            continue;
        }else{
            strcpy(path,argv[i]);
            //如果目标文件或目录不存在,报错并退出
            if(stat(path,&buf)==-1)
                my_err("stat",__LINE__);
            if(S_ISDIR(buf.st_mode)){//argv[i]是一个目录
                //如果目录的最后一格字符不是'/',就把'/'加上
                if(path[strlen(argv[i])-1]!='/'){
                    path[strlen(argv[i])]='/';
                    path[strlen(argv[i])+1]='\0';
                }
                else path[strlen(argv[i])]='\0';
                //也是调用显示目录的函数
                display_dir(flag_param,path);
                i++;
            }
            else{//argv[i]是一个文件
                display(flag_param,path);
                i++;
            }
        }
    } while (i<argc);
    return 0;
}

这里说一下argc和argv,不然可能搞不懂。

运行程序时,如果啥都不跟,直接./a.out这种的话,argc默认为1,argv[0]是程序名字,如果后面带了参数,比如这样

./a.out arg1 arg2 arg3

那argc就是4,argv[1],argv[2],argv[3]存的是参数的字符串

所以argv代码里都是从1开始,因为argv[0]默认存的是程序名称。

编译运行一下

结果还是很完美的

一整个源码也在这,方便直接抄了,但是没有注释

#include<cstdlib>
#include<cstring>
#include <cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
#include<dirent.h>
#include<linux/limits.h>
#include<pwd.h>
#include<grp.h>
#include<algorithm>
using namespace std;
#define PARAM_NONE 0
#define PARAM_A 1
#define PARAM_L 2
#define MAXROWLEN 80

int g_leave_len=MAXROWLEN;
int g_maxlen;
//自定义错误处理函数
void my_err(const char *err_string,int line){
    fprintf(stderr,"line:%d ",line);
    perror(err_string);
    exit(1);
}
int cmp(const void *a, const void *b)
{
    return ((char *)a)[0] - ((char *)b)[0];
}
void display_attribute(struct stat buf,char *name){
    char buf_time[32];
    struct passwd *psd;
    struct group *grp;
    if(S_ISLNK(buf.st_mode))
        printf("l");
    else if(S_ISREG(buf.st_mode))
        printf("-");
    else if(S_ISDIR(buf.st_mode))
        printf("d");
    else if(S_ISCHR(buf.st_mode))
        printf("c");
    else if(S_ISBLK(buf.st_mode))
        printf("b");
    else if(S_ISSOCK(buf.st_mode))
        printf("s");
    else if(S_ISFIFO(buf.st_mode))
        printf("f");
    
    if(buf.st_mode&S_IRUSR)
        printf("r");
    else printf("-");
    if(buf.st_mode&S_IWUSR)
        printf("w");
    else printf("-");
    if(buf.st_mode&S_IXUSR)
        printf("x");
    else printf("-");

    if(buf.st_mode&S_IRGRP)
        printf("r");
    else printf("-");
    if(buf.st_mode&S_IWGRP)
        printf("w");
    else printf("-");
    if(buf.st_mode&S_IXGRP)
        printf("x");
    else printf("-");

    if(buf.st_mode&S_IROTH)
        printf("r");
    else printf("-");
    if(buf.st_mode&S_IWOTH)
        printf("w");
    else printf("-");
    if(buf.st_mode&S_IXOTH)
        printf("x");
    else printf("-");

    printf("   ");

    psd=getpwuid(buf.st_uid);
    grp=getgrgid(buf.st_gid);
    printf("%4d",buf.st_nlink);
    printf("%-8s",psd->pw_name);
    printf("%-8s",grp->gr_name);

    printf("%6d",buf.st_size);
    strcpy(buf_time,ctime(&buf.st_mtime));
    buf_time[strlen(buf_time)-1]='\0';
    printf("  %s",buf_time);
}

void display_single(char *name){
    int i,len;
    if(g_leave_len<g_maxlen){
        printf("\n");
        g_leave_len=MAXROWLEN;
    }
    len=strlen(name);
    len=g_maxlen-len;
    printf("%-s",name);
    for(i=0;i<len;i++){
        printf(" ");
    }
    printf("  ");
    g_leave_len-=(g_maxlen+2);
}
void display(int flag,char *pathname){
    int i,j;
    struct stat buf;
    char name[NAME_MAX+1];
    for(i=0,j=0;i<strlen(pathname);i++){
        if(pathname[i]=='/'){
            j=0;
            continue;
        }
        name[j++]=pathname[i];
    }
    name[j]='\0';

    if(lstat(pathname,&buf)==-1)
        my_err("stat",__LINE__);
    switch (flag)
    {
    case PARAM_NONE:
        if(name[0]!='.'){
            display_single(name);
        }
        break;
    case PARAM_A:
        display_single(name);
        break;
    case PARAM_L:
        if(name[0]!='.'){
            display_attribute(buf,name);
            printf(" %s-\n",name);
        }
        break;
    case PARAM_A+PARAM_L:
        display_attribute(buf,name);
        printf(" %-s\n",name);
        break;
    default:
        break;
    }
}

void display_dir(int flag_param,char *path){
    DIR *dir;
    struct dirent *ptr;
    int count=0;
    char filenames[256][PATH_MAX+1],temp[PATH_MAX+1];

    dir=opendir(path);
    if(dir==nullptr)
        my_err("opendir",__LINE__);
    while((ptr=readdir(dir))!=nullptr){
        if(g_maxlen<strlen(ptr->d_name))
            g_maxlen=strlen(ptr->d_name);
        count++;
    }
    closedir(dir);

    if (count>256)
    {
        my_err("too maney files under this dir",__LINE__);
    }
    int i,j,len=strlen(path);
    dir=opendir(path);
    for(i=0;i<count;i++){
        ptr=readdir(dir);
        if(ptr==nullptr)
            my_err("readdir",__LINE__);
        strncpy(filenames[i],path,len);
        filenames[i][len]='\0';
        strcat(filenames[i],ptr->d_name);
        filenames[i][len+strlen(ptr->d_name)]='\0';
    }
    
    qsort(filenames,count,sizeof(filenames[0]),cmp);
    for(i=0;i<count;i++)
        display(flag_param,filenames[i]);
    closedir(dir);

    if((flag_param&PARAM_L)==0)
        printf("\n");
}
int main(int argc,char **argv){
    int i,j,k,num;
    char path[PATH_MAX+1];
    char param[32];
    int flag_param=PARAM_NONE;
    struct stat buf;
    j=0;
    num=0;
    for(i=1;i<argc;i++){
        if(argv[i][0]=='-'){
            for(k=1;k<strlen(argv[i]);k++,j++){
                param[j]=argv[i][k];
            }
        num++;
        }
    }
    for(int i=0;i<j;i++){
        if(param[i]=='a'){
            flag_param|=PARAM_A;
            continue;
        }
        else if(param[i]=='l'){
            flag_param|=PARAM_L;
            continue;
        }else{
            printf("my_ls:invalid option -%c\n",param[i]);
            exit(1);
        }
    }
    param[j]='\0';
    if((num+1)==argc){
        strcpy(path,"./");
        path[2]='\0';
        display_dir(flag_param,path);
        return 0;
    }
    i=1;
    do
    {
        if(argv[i][0]=='-'){
            i++;
            continue;
        }else{
            strcpy(path,argv[i]);
            if(stat(path,&buf)==-1)
                my_err("stat",__LINE__);
            if(S_ISDIR(buf.st_mode)){
                if(path[strlen(argv[i])-1]!='/'){
                    path[strlen(argv[i])]='/';
                    path[strlen(argv[i])+1]='\0';
                }
                else path[strlen(argv[i])]='\0';

                display_dir(flag_param,path);
                i++;
            }
            else{
                display(flag_param,path);
                i++;
            }
        }
    } while (i<argc);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1315658.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年【公路水运工程施工企业安全生产管理人员】考试总结及公路水运工程施工企业安全生产管理人员试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 公路水运工程施工企业安全生产管理人员考试总结根据新公路水运工程施工企业安全生产管理人员考试大纲要求&#xff0c;安全生产模拟考试一点通将公路水运工程施工企业安全生产管理人员模拟考试试题进行汇编&#xff0…

PCL点云处理之自定义生成多种类型的圆柱点云(C++)(二百二十五)

PCL点云处理之自定义生成多种类型的圆柱点云(C++)(二百二十五) 一、算法介绍1.空心圆柱点云2.实心圆柱点云二、算法实现1.生成方法1(空心)2.生成方法2(实心)一、算法介绍 根据自己指定的圆柱长度、圆柱半径、以及中心轴的方向,生成一个圆柱点云数据,保存在PCD文件中…

c#可变参数(params)关键字

通过使用 params 关键字&#xff0c;可以指定采用可变数量参数的方法参数。 可以发送参数声明中指定类型的参数的逗号分隔列表&#xff0c;也可以发送指定类型的参数数组。您也可以不发送任何参数。如果未发送任何参数&#xff0c;则参数列表的长度为零。 方法声明中的 param…

Anaconda中使用Jupyter出现’No module named ‘pymysql‘问题解决

问题截图&#xff1a; 解决办法&#xff1a; 一.找到Anaconda所在文件夹&#xff0c;文件夹处输入 cmd 进入命令控制 二. 在打开的cmd中输入‘conda install pymysql’ 三、输入y 安装完成~ 测试&#xff1a; import pandas as pd from sqlalchemy import create_engine …

同义词替换降低论文抄袭率的有效性探讨 papergpt

大家好&#xff0c;今天来聊聊同义词替换降低论文抄袭率的有效性探讨&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 标题&#xff1a;同义词替换降低论文抄袭率的有效性探…

Redis实现延迟队列

目录 一、什么是延时队列 二、延时队列的应用 三、举例说明 我的设计思想: 一、什么是延时队列 延时队列相比于普通队列最大的区别就体现在其延时的属性上&#xff0c;普通队列的元素是先进先出&#xff0c;按入队顺序进行处理&#xff0c;而延时队列中的元素在入队时会指定…

【Android12】WindowManagerService架构分析

Android WindowManagerService架构分析 WindowManagerService(以下简称WMS) 是Android的核心服务。WMS管理所有应用程序窗口(Window)的Create、Display、Update、Destory。 因为Android系统中只有一个WMS&#xff08;运行在SystemServer进程&#xff09;&#xff0c;可以称其为…

拼多多ID取商品详情API:电商行业的秘密武器与实时数据获取的智慧之路

一、引言 电商行业是一个不断发展和创新的领域&#xff0c;各种电商平台不断涌现&#xff0c;为消费者提供了更加便捷和多样化的购物体验。拼多多作为中国电商市场的一匹黑马&#xff0c;以其独特的社交电商模式和丰富的商品资源&#xff0c;吸引了大量用户。为了满足用户对商…

多模态融合-MVP

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言在这里插入图片描述 通过将激光点云3D BBox投影道2D图像,可以发现激光对远处的目标检测要弱于传统的2D detector,所以作者想用2D的图像信息去补充3D的点云信息。一、MVP优势二、MVP方法1.Lid…

【QT】非常简单的登录界面实现

本系列是作者自学实践过程的记录 本文是关于登录界面设计 有问题欢迎讨论 效果图&#xff1a; 一、创建项目和主界面 创建Qt Widget Application 这里我们使用qmake而不是cmake 这是主界面&#xff0c;登录界面等后面再创建&#xff0c;这里要勾选上generate form&#xff0…

AI智能化办公:ChatGPT使用方法与技巧

文章目录 ChatGPT简介✨ChatGPT的使用方法✨登录与访问发送请求调整参数 ChatGPT技巧分享✨清晰的提问实验不同的温度值多轮对话 图书推荐✨AI智能化办公内容简介获取方式 AI短视频内容简介获取方式 随着人工智能技术的不断发展&#xff0c;AI助手在办公场景中扮演着越来越重要…

windows10 php8连接sql server

一、环境安装 文章目录 一、环境安装1.安装php拓展2.在 Windows 上安装PHP驱动程序3.在 Windows 上安装ODBC驱动 二、php连接sqlserver三、注意事项数据库相关设置相关语法sqlsrv_fetch_array 的示例&#xff1a;sqlsrv_fetch 的示例&#xff1a;echo 和 print_r 的不同 所用资…

抠图软件哪个好用?什么软件可以抠图换背景?

抠图软件哪个好用&#xff1f;在图片处理中&#xff0c;抠图换背景是一项常见的操作。很多新手可能会对此感到困惑&#xff0c;不知道应该使用什么软件来进行抠图换景。实际上&#xff0c;现在市面上有很多图片处理软件都具备抠图换背景的功能&#xff0c;每款软件都有其优缺点…

王世军:铁笔翰墨染丹青 九峰冠华传千古

鸡是十二生肖中一员&#xff0c;在民间过年时常被剪成窗花&#xff0c;贴于窗户大门上。为表达人们对鸡的喜爱&#xff0c;将正月初一定为“鸡日”&#xff0c;鸡谐音“吉”&#xff0c;意为大吉大利&#xff0c;讨个好彩头。鸡又为“五德之君”&#xff0c;鸡的五德谓之文、武…

前端基础——鼠标事件对象属性和方法

button:0(未按下)1(左键)2(右键)4(中键) clientX/clientY(表示事件在客户端区域的水平和垂直坐标,左上为原点) ctrlKey表示鼠标事件发生时是否按下了ctrl键 MouseEvent.offsetX和MouseEvent.offsetY表示鼠标相对于目标节点内部填充区域的偏移量 MouseEvent.screenX和MouseE…

终端安全管理软件安装详细攻略来了

随着信息技术的不断发展&#xff0c;终端安全管理软件在企业和组织中发挥着越来越重要的作用。为了确保终端设备的安全和稳定运行&#xff0c;安装终端安全管理软件是必不可少的。以下是一份终端安全管理软件的安装详细攻略&#xff0c;供大家参考。 一、选择合适的软件 首先&…

空洞文件读取空洞部分的返回值

在空洞文件中&#xff0c;未显式写入的部分被称为"空洞"。当读取空洞部分时&#xff0c;系统会返回字节值为0的数据。 这意味着&#xff0c;当你在空洞文件中读取一个偏移量处的数据&#xff0c;而该偏移量位于空洞部分时&#xff0c;读取操作将返回一个全是0的字节…

2023/12/12作业

思维导图 作业&#xff1a; 成果图 代码 #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { speechernew QTextToSpeech(this); ui->setupUi(this); //一直获取当前时间 idst…

带你学C语言~指针(1)

Hello,CSDN的各位家人们&#xff0c;你们好啊&#xff01;今天&#xff0c;小赵要给大家分享的C语言知识是指针&#xff0c;相信不少家人们都或多或少被指针搞得晕头转向&#xff0c;小赵一开始也是&#xff0c;但后来小赵经过不断地努力学习&#xff0c;终于将这里面的知识弄懂…

【Anaconda】Ubuntu anaconda使用(新建环境、最小化安装Tensorflow, CUDA对应关系)

Ubuntu anaconda使用&#xff08;新建环境、最小化安装Tensorflow&#xff09; 文章目录 Ubuntu anaconda使用&#xff08;新建环境、最小化安装Tensorflow&#xff09;使用conda打包虚拟环境查看已创建的环境删除虚拟环境命令下运行.ipynb文件 清华源地址&#xff1a; https:…