J'essaie de faire une acquisition de chaîne simple. Ce dont j'ai besoin, c’est d’écrire une chaîne d’entrée (stdin), qui peut contenir des espaces, et de la sauvegarder sans aucun espace entre les mots.
Jusqu'ici, j'ai écrit ce code simple qui enregistre tout (y compris les espaces), mais je ne sais pas comment faire en sorte que scanf()
ignore les espaces.
int main(){
char str[10];
scanf("%[^\n]s, str);
printf("%s", str;
}
Par exemple :
si mon entrée est: I love C programming!
ma sortie devrait être: IloveCprogramming!
J'ai essayé d'utiliser %*
, utilisé pour ignorer les caractères, mais sans succès.
Je sais aussi que je pourrais "réanalyser" la chaîne une fois enregistrée et supprimer tous les espaces, mais je dois effectuer cette acquisition aussi efficacement que possible, et réanalyser chaque chaîne pour supprimer les espaces augmentera considérablement le temps de calcul (au lieu de juste numériser et ignorer, ce qui a la complexité de O (n))
Jusqu'ici, j'ai écrit ce code simple qui enregistre tout (ainsi que Espaces), mais je ne sais pas comment faire en sorte que la fonction
scanf()
ignore les espaces.
Vous abordez la question en sens inverse de ce que font la plupart des nouveaux programmeurs C. Le problème n'est généralement pas de faire scanf
ignorer des espaces, comme c'est le cas par défaut pour la plupart des types de champs, et en particulier pour les champs %s
. Les espaces sont généralement reconnus comme des délimiteurs de champs. Ainsi, non seulement les espaces de début sont ignorés, mais ils ne sont pas non plus lus à l'intérieur des champs. Je suppose que c'est parce que vous le savez que vous utilisez un champ %[
.
Mais vous ne pouvez pas avoir votre gâteau et le manger aussi. La directive de champ %[^\n]
indique que les données à lire consistent en une série de caractères non nouveaux. scanf
lira fidèlement tous ces caractères et les transférera dans le tableau que vous désignez . Vous n'avez pas la possibilité de demander à scanf
d'éviter de transférer certains des caractères que vous avez décrits comme faisant partie du champ.
Si vous souhaitez continuer à utiliser scanf
, vous avez deux options:
Une autre réponse décrit déjà comment faire le premier. Voici comment vous pouvez faire le dernier:
int main(void) {
int field_count;
do {
char str[80];
char tail;
field_count = scanf("%79[^ \n]%c", str, &tail));
if (field_count == 0) {
// No string was scanned this iteration: the first available char
// was a space or newline. Consume it, then proceed appropriately.
field_count = scanf("%c", &tail);
if (field_count != 1 || tail == '\n') {
// newline, end-of-file, or error: break out of the loop
break;
} // else it's a space -- ignore it
} else if (field_count > 0) {
// A string was scanned; print it:
printf("%s", str);
if (field_count == 2) {
// A trailing character was scanned, too; take appropriate action:
if (tail == '\n') {
break;
} else if (tail != ' ') {
putchar(tail);
} // else it is a space; ignore it
}
} // else field_count == EOF
} while (field_count != EOF);
}
Choses à noter :
scanf
%79[^ \n]
. Sans une largeur de champ, il existe un risque sérieux de dépasser la limite de votre tableau (ce qui doit être au moins un caractère plus long que le champ pour permettre un terminateur de chaîne).[
est un type de champ, pas un qualificatif. s
est un type de champ distinct qui gère également les chaînes, mais a un comportement différent; aucun champ s
n'est utilisé ici.scanf
vous indique le nombre de champs ayant été analysés avec succès, ce qui peut être inférieur à celui décrit dans la chaîne de format en cas d'incompatibilité entre entrée et format, si la fin de l'entrée est atteinte ou si une erreur d'E/S est atteinte. se produit. Ces possibilités doivent être prises en compte.%c
, est effectivement analysé, il vous permet de déterminer si le champ de chaîne précédent s'est terminé parce que la largeur du champ était épuisée sans atteindre un espace ou une nouvelle ligne, car un espace a été observé ou un nouveau trait a été utilisé. observé. Chacun de ces cas nécessite une manipulation différente.scanf
ignore les espaces de type pour les types most , %[
et %c
sont deux des trois exceptions.' '
); elle ne saute pas d'autres caractères d'espacement, tels que les tabulations horizontales et verticales, les retours à la ligne, les sauts de formulaire, etc. Cette approche peut également être adaptée, mais ce qui est présenté suffit à démontrer.Vous utilisez le mauvais outil pour le travail. Vous devez utiliser getc
Et faire ce qui suit
int ch;
char str[10];
// Loop until either loop reaches 9 (need one for null character) or EOF is reached
for (int loop = 0; loop < 9 && (ch = getc(stdin)) != EOF; ) {
if (ch != ' ' ) {
str[loop] = ch;
++loop;
}
}
str[loop] = 0;
printf("%s", str);
Pas de re-scan nécessaire
Si vous souhaitez supprimer d'autres espaces blancs (en plus de ''), vous pouvez également incorporer la fonction de bibliothèque Cisspace (.), qui teste les caractères d'espaces blancs standard suivants:
'' (0x20) espace (SPC)
'\ t' (0x09) onglet horizontal (TAB)
'\ n' (0x0a) nouvelle ligne (LF)
'\ v' (0x0b) onglet vertical (VT)
'\ f' (0x0c) alimentation (FF)
'\ r' (0x0d) retour chariot (CR)
Cet exemple incorpore une fonction utilisant la fonction de bibliothèque isspace(.);
et fournit une méthode pour effacer tous les espaces blancs standard d'une chaîne C.
int main(void)
{
char string[] = {"this contain's \n whitespace\t"};
int len = strlen(string);
char out[len+1];// +1 for null terminator
//(accommodates when input contains no whitespace)
int count = clean_whitespace(string, out);
return 0;
}
int clean_whitespace(const char *in, char *out)
{
int len, count=0, i;
if((in) && (out))
{
len = strlen(in);
for(i=0;i<len;i++)
{
if(!isspace(in[i]))
{
out[count++] = in[i];
}
}
out[count]=0;//add null terminator.
}
return count;
}
scanf()
n'est pas utile dans ce but, en effet vous n'avez même pas besoin d'un tampon pour effacer les espaces d'une ligne d'entrée: lisez simplement les octets un par un, ignorez les espaces, affichez les autres et arrêtez-vous à la nouvelle ligne ou à l'EOF:
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (c != ' ') {
putchar(c);
}
if (c == '\n') {
break;
}
}
return 0;
}
Notez également que votre code a des problèmes:
scanf()
n'est pas terminées
est incorrecte, le format est simplement %[^\n]
scanf("%9[^\n]", str);
scanf()
pour éviter de transmettre un tableau non initialisé à printf
si la conversion échoue, par exemple sur une ligne ou un fichier vide.Vous pouvez utiliser scanf()
comme un moyen inefficace de lire les caractères tout en ignorant les espaces, avec char c; while (scanf(" %c", &c) == 1) { putchar(c); }
mais vous ne pourriez pas détecter la fin de la ligne.
Je poste ceci pour démontrer qu'il est également possible de résoudre ce problème simplement avec scanf.
int main() {
char a[10];
for(int i = 0; i < 10 ; i++){
scanf("%c", &a[i]);
if( a[i] == ' ')
i--;
}
}
celui ci-dessus scanne simplement 10 caractères sans espaces entre eux.
for(int i = 0; i < 9; i++){
printf("%c,", a[i]);
}
printf("%c", a[9]);
et c'est le moyen d'utiliser si vous voulez remplacer les espaces par autre chose, par exemple: ','
Si vous voulez que l'entrée soit composée de plus de caractères, définissez simplement une nouvelle variable x et changez le 10 en x et le 9 en x-1