Estou tentando obter alguns dados do usuário e enviá-los para outra função no gcc. O código é algo como isto.
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
No entanto, acho que ele tem um \n
caractere de nova linha no final. Então, se eu entrar John
, acaba enviando John\n
. Como faço para remover isso \n
e enviar uma string adequada.
if (!fgets(Name, sizeof Name, stdin))
(pelo menos não use duas negações, e =!)if (fgets(Name, sizeof Name, stdin)) {
.if (fgets(Name, sizeof Name, stdin) == NULL ) {
!
:Respostas:
A maneira um pouco feia:
A maneira um pouco estranha:
Observe que a
strtok
função não funciona como esperado se o usuário digitar uma string vazia (ou seja, pressionar apenas Enter). Deixa o\n
personagem intacto.Existem outros também, é claro.
fonte
strtok()
será protegida por thread (ela usará o armazenamento local do thread para o estado 'inter-call'). Dito isto, ainda é geralmente melhor usar astrtok_r()
variante não padrão (mas comum o suficiente) .strtok
abordagem (e funciona com entradas vazias). De fato, uma boa maneira de implementarstrtok
é usarstrcspn
estrspn
.*strchrnul(Name, '\n') = '\0';
.strchr(Name, '\n') == NULL
, além de "entrada muito longa para buffer, erro de sinalizador", existem outras possibilidades: O último texto inseridostdin
não terminou com um'\n'
ou um caractere nulo incorporado raro foi lido.Talvez a solução mais simples use uma das minhas funções pouco conhecidas favoritas
strcspn()
:Se você deseja que ele também manipule
'\r'
(por exemplo, se o fluxo for binário):A função conta o número de caracteres até atingir a
'\r'
ou a'\n'
(em outras palavras, encontra o primeiro'\r'
ou'\n'
). Se não acertar nada, ele pára no'\0'
(retornando o comprimento da corda).Observe que isso funciona bem, mesmo se não houver nova linha, porque
strcspn
para em a'\0'
. Nesse caso, a linha inteira está simplesmente substituindo'\0'
por'\0'
.fonte
buffer
que começa com'\0'
, algo que provoca dor pelabuffer[strlen(buffer) - 1] = '\0';
abordagem.strcspn()
. Uma das funções mais úteis da biblioteca, IMO. Decidi escrever e publicar um monte de hacks C comuns como este hoje; umastrtok_r
implementação usandostrcspn
estrspn
foi uma das primeiras: codepad.org/2lBkZk0w ( Aviso: não posso garantir que seja sem bugs; foi escrito às pressas e provavelmente possui alguns). Não sei onde os publicarei ainda, porém, pretendo fazê-lo no espírito dos famosos "pequenos truques de manipulação".fgets()
strcspn()
strlen
fgets()
entrada . Que também é sempre a primeira nova linha.fonte
fgets(buf, size, ....)
->strlen(buf) == 0
. 1)fgets()
lê como o primeirochar
a'\0'
. 2)size == 1
3)fgets()
retorna,NULL
então obuf
conteúdo pode ser qualquer coisa. (Embora o código do OP teste NULL) Sugerir:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
ln
seria -1, exceto o fato desize_t
não ter sinal, gravando assim na memória aleatória. Eu acho que você deseja usarssize_t
e verificar seln
é> 0.strlen
) pode ser implementada com muito mais eficiência do que uma pesquisa simples de caractere por caractere. Por esse motivo, consideraria esta solução melhor do que umastrchr
ou comstrcspn
base.Abaixo está uma abordagem rápida para remover um potencial
'\n'
de uma string salva porfgets()
.Utiliza
strlen()
, com 2 testes.Agora use
buffer
elen
conforme necessário.Este método tem o benefício colateral de um
len
valor para o código subseqüente. Pode ser facilmente mais rápido questrchr(Name, '\n')
. Ref YMMV, mas ambos os métodos funcionam.buffer
, do originalfgets()
não conterá em"\n"
algumas circunstâncias:A) A linha era muito longa para
buffer
que apenas ochar
anterior'\n'
seja salvo embuffer
. Os caracteres não lidos permanecem no fluxo.B) A última linha do arquivo não terminou com a
'\n'
.Se a entrada incorporou caracteres nulos
'\0'
em algum lugar, o comprimento relatado porstrlen()
não incluirá o'\n'
local.Problemas de outras respostas:
strtok(buffer, "\n");
falha ao remover o'\n'
quandobuffer
é"\n"
. A partir desta resposta - alterada após esta resposta para avisar sobre esta limitação.O seguinte falha em raras ocasiões, quando a primeira
char
leiturafgets()
é'\0'
. Isso acontece quando a entrada começa com um incorporado'\0'
. Entãobuffer[len -1]
torna-sebuffer[SIZE_MAX]
acessar a memória certamente fora da faixa legítima debuffer
. Algo que um hacker pode tentar ou encontrar na leitura tola de arquivos de texto UTF16. Esse era o estado de uma resposta quando essa resposta foi escrita. Posteriormente, um não-OP editou-o para incluir um código como o de verificação desta resposta""
.sprintf(buffer,"%s",buffer);
é um comportamento indefinido: ref . Além disso, ele não salva nenhum espaço em branco inicial, separador ou final. Agora excluído .[Editar devido a uma boa resposta posterior ] Não há problemas com o liner 1
buffer[strcspn(buffer, "\n")] = 0;
além do desempenho em comparação com astrlen()
abordagem. O desempenho no corte geralmente não é um problema, pois o código está executando a E / S - um buraco negro no tempo da CPU. Se o código a seguir precisar do comprimento da string ou tiver alto desempenho, use estastrlen()
abordagem. Caso contrário,strcspn()
é uma boa alternativa.fonte
strlen(buffer)
quando o tamanho do buffer é alocado dinamicamente usandomalloc
?buffer = malloc(allocation_size); length = strlen(buffer);
está incorreto - os dados na memória apontados porbuffer
são desconhecidos.buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);
está OKDireto para remover '\ n' da saída do fgets, se todas as linhas tiverem '\ n'
De outra forma:
fonte
strnlen
vez destrlen
.n
não aumenta magicamente a segurança; nesse caso, de fato, tornaria o código mais perigoso. Da mesma formastrncpy
, uma função terrivelmente insegura. A postagem à qual você vinculou é um mau conselho.""
). Também nãostrlen()
retorna .size_t
int
Para um corte único \ \ n,
para vários cortes \ \ n ',
fonte
if
quando você pode simplesmente escrever uma condição usando&&
? Essewhile
loop tem uma estrutura estranha; poderia simplesmente serwhile (length > 0 && string[length-1] == '\n') { --length; string[length] = '\0'; }
.size_t length = strlen(string); if (length > 0 && string[length-1] == '\n') { string[length-1] = '\0'; }
. Isso também reflete melhor a segunda definição (apenas usando emif
vez dewhile
).My Newbie way ;-) Por favor, deixe-me saber se isso está correto. Parece estar funcionando para todos os meus casos:
fonte
As etapas para remover o caractere de nova linha da maneira talvez mais óbvia:
NAME
usandostrlen()
, headerstring.h
. Observe questrlen()
não conta a terminação\0
.\0
caractere (sequência vazia). Nesse casosl
seria0
porque,strlen()
como eu disse acima, não conta\0
e para na primeira ocorrência:'\n'
. Se for esse o caso, substitua\n
por a\0
. Observe que as contagens de índice começam em,0
portanto, precisaremosNAME[sl - 1]
:Observe que se você pressionar Enter apenas na
fgets()
solicitação de sequência (o conteúdo da sequência era composto apenas por um caractere de nova linha), a sequênciaNAME
será uma sequência vazia posteriormente.if
declaração usando o operador lógico&&
:Se você preferir uma função para usar essa técnica, manipulando as
fgets
seqüências de saída em geral sem redigitar todas as vezes, aqui estáfgets_newline_kill
:No seu exemplo fornecido, seria:
Observe que esse método não funciona se a string de entrada tiver incorporado
\0
s . Se fosse esse o casostrlen()
, retornaria apenas a quantidade de caracteres até o primeiro\0
. Mas essa não é uma abordagem comum, já que as funções de leitura de cordas geralmente param na primeira\0
e levam a string até esse caractere nulo.Além da pergunta por si só. Tente evitar negações duplas que tornam a sua unclearer código:
if (!(fgets(Name, sizeof Name, stdin) != NULL) {}
. Você pode simplesmente fazerif (fgets(Name, sizeof Name, stdin) == NULL) {}
.fonte
\n
por um\0
no final de uma string é uma maneira de "remover" a nova linha. Mas a substituição de\n
caracteres dentro de uma sequência altera fundamentalmente a sequência. Não é incomum ter seqüências de caracteres com vários caracteres de nova linha intencionais, e isso efetivamente cortaria as extremidades dessas strings. Para remover essas novas linhas, o conteúdo da matriz precisa mudar para a esquerda para substituir o\n
.fgets()
?fgets()
. Mas não entendo sua objeção: é você quem propõe um código para lidar com várias novas linhas.strlen
etc. Justificação para não ser uma duplicata: 1. Explicação do código por etapas. 2. Fornecido como função e solução baseada em contexto. 3. Dica para evitar expressões de dupla negação.Tim Čas um liner é incrível para seqüências de caracteres obtidas por uma chamada para fgets, porque você sabe que elas contêm uma única nova linha no final.
Se você estiver em um contexto diferente e quiser manipular seqüências de caracteres que possam conter mais de uma nova linha, talvez esteja procurando por strrspn. Não é POSIX, o que significa que você não o encontrará em todos os Unices. Eu escrevi um para minhas próprias necessidades.
Para quem procura um equivalente Perl chomp em C, acho que é isso (o chomp remove apenas a nova linha à direita).
A função strrcspn:
fonte
'\n'
(ou se a string é""
).strrcspn
para quando não há\n
.goto end;
vez dereturn len;
?goto
s no seu código: um inútilgoto
que pode ser substituído por umareturn
declaração e um reversogoto
que é considerado mau. Usandostrchr
ajuda a implementarstrrspn
estrrcspn
de uma forma mais simples:size_t strrspn(const char *s, const char *accept) { size_t len = strlen(s); while (len > 0 && strchr(accept, s[len - 1])) { len--; } return len; }
esize_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
Se usar
getline
é uma opção - não negligenciando seus problemas de segurança e se você deseja colocar ponteiros - você pode evitar as funções de cadeia, poisgetline
retorna o número de caracteres. Algo como abaixoNota : Os [ problemas de segurança ] com
getline
não devem ser negligenciados.fonte
A função abaixo faz parte da biblioteca de processamento de strings que estou mantendo no Github. Remove caracteres indesejados de uma string, exatamente o que você deseja
Um exemplo de uso pode ser
Você pode verificar outras funções disponíveis ou até contribuir com o projeto :) https://github.com/fnoyanisi/zString
fonte
*
em*src++;
e fazerbad
,token
ed
const char *
. Além disso, por que não usar emstrchr
vez dezChrSearch
?*src
não pode estar'\0'
em suazStrrmv
função.strchr
Você deveria tentar. Esse código basicamente percorre a string até encontrar o '\ n'. Quando encontrado, '\ n' será substituído pelo terminador de caracteres nulos '\ 0'
Observe que você está comparando caracteres e não seqüências de caracteres nesta linha, então não há necessidade de usar strcmp ():
pois você usará aspas simples e não aspas duplas. Aqui está um link sobre aspas simples vs duplas, se você quiser saber mais
fonte
for(int i = 0; i < strlen(Name); i++ )
chamarástrlen(Name)
muitas vezes (alterações de loopName[]
), portanto, com um comprimentoN
, essa é umaO(N*N)
solução. Apenas uma chamada parastrlen(Name)
, se houver, é necessária para fornecer uma solução O (N) `. Nãoint i
está claro por que é usado em vez desize_t i
. Considerefor(size_t i = 0; i < Name[i]; i++ )
for (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }
Tente este:
fonte
len = strlen(str)
pode estourar:strlen
retornasize_t
, nãoint
. O que há com osif (len>0) if (...)
condicionais estranhos ? Você não conhece&&
? Se você deseja remover várias instâncias finais de CR / LF, por que se limitar a 5? Por que não remover todos eles? Por que a função tem umint
tipo de retorno quando sempre retorna0
? Por que não apenas retornarvoid
?