单向链表保存/etc/passwd
使用单向链表保存/etc/passwd的内容,user结构体如下所示:
struct user {
struct user *next;
char *name;
unsigned int uid;
unsigned int gid;
char home[64];
char shell[64];
};
sscanf函数
sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。sscanf可用来进行数据类型或进制转换以及按特定规则读取源字符串的特定规则。
常见几种用法:
- %[abc]读取a、b、或c的任意一员,[a-z]表示匹配小写字母,[a-z0-9]表示匹配小写字母及数字
- %[^a-z]读取不在a-z之间的字符串,如果碰到 a-z 之间的字符则停止
- %[^=]读取字符串直到碰到=号
- %[^=]%s前面带号表示不保存变量。跳过字符串中以=结尾的子串而读后包括=在内的后面部分子串
在C语言中,sscanf 函数是用于从字符串中按照指定格式解析数据的函数。在格式字符串中,%m 和 %u 是两种格式化说明符,用于解析不同类型的数据。
1. %m 格式化说明符:
%m 用于解析一个字符串,并为其分配内存。它的用法类似于 %s,但是 %m 可以自动分配足够的内存来存储字符串,而不需要预先分配。这在避免内存溢出和缓冲区溢出问题方面非常有用。
在下面这个例子中,%m[^\n] 解析一行字符串,并为 output 分配足够的内存来存储它。
char *input = "Hello, world!";
char *output = NULL;
sscanf(input, "%m[^\n]", &output);
printf("Output: %s\n", output);
free(output);
2. %u 格式化说明符:
%u 用于解析无符号整数(unsigned int)。它期望在格式化字符串中匹配一个无符号整数,并将其解析为对应的无符号整数类型。
在这个例子中,字符串 “12345” 被解析为无符号整数值 12345。
unsigned int value;
sscanf("12345", "%u", &value);
printf("Value: %u\n", value);
答案解析:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<err.h>
#include<string.h>
#define BUF_SIZE 512
struct user* parse_user(char *str);
struct user {
struct user *next;
char *name;
unsigned int uid;
unsigned int gid;
char home[64];
char shell[64];
};
struct user* parse_user(char *str){
struct user* new_user = (struct user*)malloc(sizeof(struct user));
if(new_user == NULL) {
err(EXIT_FAILURE, "malloc");
}
memset(new_user, 0, sizeof(*new_user));
int flags = sscanf(str, "%m[^:]:%*[^:]:%u:%u:%*[^:]:%63[^:]:%63s", \
&(new_user->name), &(new_user->uid), &(new_user->gid),new_user->home, new_user->shell) == 5
| sscanf(str, "%m[^:]:%*[^:]:%u:%u::%63[^:]:%63s", \
&(new_user->name), &(new_user->uid), &(new_user->gid),new_user->home, new_user->shell) == 5;
if(flags){
printf("%s\t %u\t %u\t %s\t %s\n", \
new_user->name, new_user->uid, new_user->gid, new_user->home, new_user->shell);
return new_user;
}
if(new_user && new_user->name) free(new_user->name);
if(new_user) free(new_user);
return NULL;
}
int main(int argc, char *argv[]){
FILE* fp = fopen("/etc/passwd", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
char buf[BUF_SIZE];
struct user* head = NULL;
struct user* cur = NULL;
while(fgets(buf, sizeof(buf), fp)){
struct user* newNode = parse_user(buf);
newNode->next = NULL;
if(head == NULL){
head = newNode;
cur = newNode;
}else{
cur->next = newNode;
cur = newNode;
}
}
fclose(fp);
cur = head;
while(cur != NULL){
cur = cur->next;
}
cur = head;
while(cur != NULL){
struct user* tmp = cur;
cur = cur->next;
free(tmp);
}
return 0;
}
自己写的答案,有什么不足请大佬们指正,加快学习进度。
欢迎关注知乎账号:勤奋的小牛