我有点像C的初学者,所以请原谅任何粗心的错误!
我正在尝试使用printf()打印一些格式化值,但即使没有'\ n',它也会在输出中间开始换行! 问题出在第442行的list_topic函数中。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
typedef struct
{
int t_id;
char t_name[35];
char date_creation[30];
char last_post_date[30];
int sub_users;
int num_posts;
char t_desc[500];
} topic;
typedef struct
{
int u_type;
int t_maxreach;
int u_sub_topic[15];
char u_name[16];
char u_pass[16];
} utilizador;
void instalar();
void menu_inicial();
void menu_admin();
void menu_topic();
void menu_user();
void login();
void options();
void topic_gest();
void user_gest();
void stats();
void new_topic();
void alt_topic();
void rmv_topic();
void list_topic();
void new_user();
void val_new_user();
void list_user();
void edit_user();
void erro();
void erro_app();
void erro_cred();
int main()
{
struct stat st = { 0 };
int n;
if (stat("SUP", &st) == -1) //verifica se o diretório já existe
{
instalar(); //chama a função instalar()
}
menu_inicial(); //chama a função menu_inicial()
scanf("%d", &n); //lê a opção escolhida pelo utilizador
while (n != 2)
{
switch (n)
{
case 1: {login(); break; }
default: {erro(); }
}
menu_inicial(); //chama a função menu_inicial()
scanf("%d", &n); //lê a opção escolhida pelo utilizador
}
system("clear");
return 0;
}
void instalar() //cria o diretório base e o administrador padrão
{
{
system("clear");
printf("O programa não está instalado. Deseja instalar? [s/n]\n");
char t; //recebe input
for (int s = 0; s == 0;)
{
scanf("%c", &t);
getchar();
if (t == 's') //se o input for 's' instala
{
system("clear");
printf("A instalar...\n\n");
mkdir("SUP", 0700);
mkdir("SUP/Topicos/", 0700);
FILE *ft = fopen("SUP/Topicos/topicos.dat", "wb");
topic tbase;
tbase.t_id = 1;
strcpy(tbase.t_name, "Topico inicial");
time_t curtime;
time(&curtime);
strcpy(tbase.date_creation, ctime(&curtime));
strcpy(tbase.last_post_date, ctime(&curtime));
tbase.sub_users = 0;
tbase.num_posts = 0;
strcpy(tbase.t_desc, "topic desc");
fwrite(&tbase, sizeof(topic), 1, ft);
fclose(ft);
//testar
topic input;
ft = fopen("SUP/Topicos/topicos.dat", "rb");
while (fread(&input, sizeof(topic), 1, ft))
{
printf("id = %d \nname = %s \ntopic desc = %s \nlast post date = %s \nsubscribed users = %d \nnumber of posts = %d", input.t_id, input.t_name, input.t_desc, input.last_post_date, input.sub_users, input.num_posts);
}
getchar();
FILE *f = fopen("SUP/utilizadores.dat", "wb");
utilizador admin;
admin.u_type = 1;
admin.t_maxreach = 0;
strcpy(admin.u_name, "admin");
strcpy(admin.u_pass, "admin");
admin.u_sub_topic[0] = tbase.t_id;
fwrite(&admin, sizeof(utilizador), 1, f);
fclose(f);
printf("Pressione a tecla ENTER para continuar...");
getchar();
break;
}
else if (t == 'n') //se o input for 'n' não instala e sai do programa
{
system("clear");
exit(0);
}
}
}
}
void menu_inicial()
{
system("clear");
printf("----------** Menu de registo **----------\n");
printf("| |\n");
printf("| 1) Login / Autenticação |\n");
printf("| 2) Sair |\n");
printf("| |\n");
printf("-----------------------------------------\n");
}
void menu_admin() //menu depois do login
{
system("clear");
printf("------------------** Menu **-------------------\n");
printf("| |\n");
printf("| 1) Gerir Tópicos |\n");
printf("| 2) Gerir Utilizadores |\n");
printf("| 3) Estatísticas |\n");
printf("| 4) Logout |\n");
printf("| |\n");
printf("-----------------------------------------------\n");
}
void menu_topic()
{
system("clear");
printf("-------------------** Gestão de Tópicos **--------------------\n");
printf("| |\n");
printf("| 1) Criar novo tópico |\n");
printf("| 2) Alterar atributos de um tópico |\n");
printf("| 3) Eliminar tópico |\n");
printf("| 4) Listar tópicos |\n");
printf("| 5) Voltar atrás |\n");
printf("| |\n");
printf("--------------------------------------------------------------\n");
}
void menu_user()
{
system("clear");
printf("---------------------** Gestão de Utilizadores **--------------------\n");
printf("| |\n");
printf("| 1) Criar novo utilizador |\n");
printf("| 2) Validar pedido de novo utilizador |\n");
printf("| 3) Listar utilizadores |\n");
printf("| 4) Editar utilizadores |\n");
printf("| 5) Voltar atrás |\n");
printf("| |\n");
printf("---------------------------------------------------------------------\n");
}
void login() //processo de autenticação do utilizador
{
system("clear");
char name[16], *pass;
int res;
utilizador input;
printf("----------** Login / Autenticação **----------\n");
printf("Nome de utilizador: ");
scanf("%s", name);
getchar();
pass = getpass("Palavra-passe: ");
FILE *f = fopen("SUP/utilizadores.dat", "rb");
while (fread(&input, sizeof(utilizador), 1, f)) //testa se as credenciais são válidas e são de administrador
{
if (input.u_type == 1)
{
res = strcmp(name, input.u_name);
res += strcmp(pass, input.u_pass);
if (res == 0)
{
break;
}
}
else if (input.u_type == 0)
{
res = strcmp(name, input.u_name);
res += strcmp(pass, input.u_pass);
if (res == 0)
{
res = 2;
break;
}
}
}
fclose(f);
switch (res)
{
case 0: {options(); break; }
case 2: {erro_app(); break; }
default: {erro_cred(); }
}
}
void options() //escolha de opções depois do login
{
int i;
menu_admin();
scanf("%d", &i);
getchar();
while (i != 4)
{
switch (i)
{
case 1: {topic_gest(); break; }
case 2: {user_gest(); break; }
case 3: {stats(); break; }
default: {erro(); }
}
menu_admin();
scanf("%d", &i);
getchar();
}
}
void topic_gest() //escolher opções de gestão de tópicos
{
int i;
menu_topic();
scanf("%d", &i);
getchar();
while (i != 5)
{
switch (i)
{
case 1: {new_topic(); break; }
case 2: {alt_topic(); break; }
case 3: {rmv_topic(); break; }
case 4: {list_topic(); break; }
default: {erro(); }
}
menu_topic();
scanf("%d", &i);
getchar();
}
}
void user_gest() //escolher opções de gestão de utilizadores
{
int i;
menu_user();
scanf("%d", &i);
getchar();
while (i != 5)
{
switch (i)
{
case 1: {new_user(); break; }
case 2: {val_new_user(); break; }
case 3: {list_user(); break; }
case 4: {edit_user(); break; }
default: {erro(); }
}
menu_user();
scanf("%d", &i);
getchar();
}
}
void stats() //mostra as estatísticas dos tópicos e dos utilizadores
{
}
void new_topic() //cria um tópico novo
{
system("clear");
topic new, filein;
FILE *f = fopen("SUP/Topicos/topicos.dat", "ab+");
printf("---------------------** Criar Novo Tópico **--------------------\n\n");
printf("Nome do tópico <máximo de 50 carateres>: ");
fgets(new.t_name, 35, stdin);
strcpy(new.t_name, strtok(new.t_name, "\n"));
if (strlen(new.t_name) > 30) //testa se o nome inserido é demasiado comprido
{
system("clear");
printf("O nome é demasiado comprido, por favor insira outro nome!\n\n");
printf("Pressione a tecla ENTER para voltar atrás...");
getchar();
return;
}
else
{
while (fread(&filein, sizeof(topic), 1, f))
{
if (strcmp(filein.t_name, new.t_name) == 0) //testa se o tópico inserido já existe
{
system("clear");
printf("Este tópico já existe, por favor insira outro nome!\n\n");
printf("Pressione a tecla ENTER para voltar atrás...");
getchar();
return;
}
}
}
rewind(f);
new.t_id = 1;
while (fread(&filein, sizeof(topic), 1, f)) //testa a id dos tópicos já registados para não terem ids duplicados
{
if (new.t_id <= filein.t_id)
{
new.t_id += 1;
printf("id = %d", new.t_id);
getchar();
}
}
printf("Descrição do tópico <máximo de 500 carateres>: ");
fgets(new.t_desc, 500, stdin);
time_t curtime;
time(&curtime);
strcpy(new.date_creation, ctime(&curtime));
strcpy(new.last_post_date, ctime(&curtime));
new.sub_users = 0;
new.num_posts = 0;
fwrite(&new, sizeof(topic), 1, f);
fclose(f);
printf("Tópico '%s' criado com sucesso!\n\n", new.t_name);
printf("Pressione a tecla ENTER para continuar...");
getchar();
}
void alt_topic()
{
system("clear");
char name[30];
printf("-------------------------** Alterar Tópico **------------------------\n\n");
printf("Insira o nome do tópico que deseja alterar: ");
fgets(name, 30, stdin);
printf("name = %s", name);
getchar();
}
void rmv_topic()
{
}
void list_topic()
{
system("clear");
printf("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
printf("| ID | Nome | Descrição | Criado em | Último post em | Utilizadores subscritos | Nº de posts |\n");
printf("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
FILE *ft = fopen("SUP/Topicos/topicos.dat", "rb");
topic input;
while (fread(&input, sizeof(topic), 1, ft))
{
printf("| %04d | %-30s | %-44s | %-25s | %-29s | %-23d | %-13d |\n", input.t_id, input.t_name, input.t_desc, input.date_creation, input.last_post_date, input.sub_users, input.num_posts);
printf("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
}
getchar();
}
void new_user()
{
}
void val_new_user()
{
}
void list_user()
{
}
void edit_user()
{
}
void erro() //dá mensagem de erro na escolha da opção
{
system("clear");
printf("Opção desconhecida!\n\n");
printf("Pressione a tecla ENTER para continuar...");
getchar();
}
void erro_app() //dá mensagem de credenciais sem autorização e sai do programa
{
system("clear");
printf("As credenciais inseridas não são credenciais de administrador!\n");
printf("Por favor use o programa CLIENTE para iniciar a sessão!\n\n");
printf("Pressione a tecla ENTER para sair...");
getchar();
system("clear");
exit(0);
}
void erro_cred() //dá mensagem de credenciais erradas e reinicia login()
{
system("clear");
printf("Nome de utilizador e/ou palavra-passe incorretos!\n\n");
printf("Pressione a tecla ENTER para continuar...");
getchar();
getchar();
login();
}
输出应该是这样的:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| ID | Nome | Descrição | Criado em | Último post em | Utilizadores subscritos | Nº de posts |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0001 | Topico inicial | topic desc | Tue May 15 12:36:03 2018 | Tue May 15 12:36:03 2018 | 0 | 0 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
但最终是这样的:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| ID | Nome | Descrição | Criado em | Último post em | Utilizadores subscritos | Nº de posts |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0001 | Topico inicial | topic desc | Tue May 15 12:36:03 2018
| Tue May 15 12:36:03 2018
| 0 | 0 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我不知道可能出现什么问题!
答案 0 :(得分:10)
您的计划存在的问题是,ctime
会在结尾处返回时间字符串,其中包含'\n'
。你可以看到假的新行总是在打印时间之后。
您可以在将其复制到指定的缓冲区后将其删除。
例如在
之后strcpy(new.date_creation, ctime(&curtime));
您可以添加
new.date_creation[strlen(new.date_creation)-1] = '\0';
您需要将此内容添加到您要创建的每个字符串ctime
(或asctime
,如果您将来再使用它)。
实际上,这个'\n'
的存在是由C标准保证的。您可以查看ctime
和asctime
的各个部分。
引用C11
,章§7.27.3.1p2
形式的字符串
asctime
函数将timeptr
指向的结构中的细分时间转换为
Sun Sep 16 01:03:52 1973\n\0