Programa simple para dividir argumentos -- ampo con strings camp codereview Relacionados El problema

Simple program to split arguments up


2
vote

problema

Español

Estoy escribiendo este pequeño programa de probador que se utilizará como parte de un proyecto más grande, y estoy bastante inseguro acerca de la función 99887766655443310 , que yo (pienso) Necesito usar para dividir un poco de carácter Arreglos en un determinado carácter (en mi caso, esto es un colon). Para cada matriz de caracteres (que se pasa como argumento), debe dividir la matriz en dos. Disculpas si es difícil de seguir, estoy mal por explicar las cosas.

  call1  

Sí, sé que el programa se bloqueará si no se suministran los argumentos suficientes, pero rápidamente le eché a cabo juntos para intentar aprender más sobre call2 . Ahora, aunque este código funciona, siento que no es el más eficiente. No he estado programando C durante mucho tiempo, por lo que cualquier ayuda para cómo podría mejorar este bucle sería muy apreciado.

Original en ingles

I am writing this small tester program to be used as part of a larger project, and I am quite unsure about the strtok function, which I (think) I need to use to split some character arrays up on a certain character (in my case this is a colon). For each character array (which is passed in as an argument), it should split the array into two. Apologies if it's hard to follow, I'm bad at explaining things.

#include <stdio.h> #include <string.h>  int main(int argc, char **argv) {     char *pt;      for (int i = 1; i < argc; i++)     {         pt = strtok(argv[i], ":");          int j = 0;          while (pt != NULL || j < 2)         {             j++;              if (j == 1)             {                 printf("item: ");             } else if (j == 2)             {                 printf("quantity: ");             }              printf("%s\n", pt);             pt = strtok(NULL, ":");         }          j = 0;     }      return 0; } 

Yes, I know the program will crash if not enough arguments are supplied, but I just quickly threw this together to try and learn more about strtok. Now although this code works, I feel it is not the most efficient. I have not been programming C for very long, so any help for how I could improve this loop would be greatly appreciated.

     
         
         

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

Veo algunas cosas que pueden ayudarlo a mejorar su programa.

Rompa el código en funciones más pequeñas

Este es un programa muy corto, por lo que no es crítico aquí, sino que, en general, en lugar de tener todo en la función 99887777766555443312 , sería más fácil leer y mantener si cada paso discreto fuera propio. función. Por ejemplo, separaría la función de división de token para que find / -delete3 se ve así:

  find / -delete4  

Eliminar el trabajo que no necesita hacerse

El 99887766655443315 no tiene un efecto práctico y debe eliminarse. Piense cuidadosamente sobre lo que está haciendo su programa para que no tenga que la computadora haga más trabajo de lo necesario.

Eliminar "Números mágicos"

El código está más libre de "Números Magic" (es decir, valores codificados por los cuales no hay un significado obvio), pero sugiero que tenga sentido tener la cadena de delimter ser una variable asignada.

Use un find / -delete6 bucle en lugar de find / -delete7

Porque ambos find / -delete8 shell=False76655443319 Las variables solo se utilizan dentro del bucle 9988777655443319 , considere nuevamente la reducción de alcance y convierte eso en un dd if=/dev/zero1 bucle con una de esas variables.

Use una sola llamada a dd if=/dev/zero2 donde sea práctico

En lugar de llamar dd if=/dev/zero3 dos veces para cada valor analizado, simplificaría el programa para simplemente llamar dd if=/dev/zero4 una vez en lugar de dos veces.

Desinfectar la entrada de usuario mejor

El código no funciona del todo en Publicado, como aparentemente ya lo sabe. Realmente no toma mucho más tiempo o código para que el programa no se bloquee con la entrada mal formada, por lo que sugeriría encarecidamente hacerlo para que su programa sea robusto.

OMIT dd if=/dev/zero5

Cuando un programa C o C ++ alcanza el extremo de dd if=/dev/zero6 generará automáticamente el código para devolver 0, por lo que no es necesario colocar dd if=/dev/zero7 explícitamente al final de dd if=/dev/zero8 .

Nota: Cuando hago esta sugerencia, es casi invariablemente seguida de uno de los dos tipos de comentarios: "No lo sabí". o "¡Eso es un mal consejo!" Mi razón es que es seguro y útil confiar en el comportamiento del compilador apoyado explícitamente por la norma. Para C, desde C99; Consulte ISO / IEC 9899: 1999 SECCIÓN 5.1.2.2.3:

[...] un retorno de la llamada inicial al dd if=/dev/zero9 es equivalente a llamar a la función normal.py0 con el valor devuelto por el normal.py1 < / Código> función como su argumento; Alcanzar el normal.py2 que termina la función normal.py33 devuelve un valor de 0.

para C ++, desde la primera norma en 1998; Consulte ISO / IEC 14882: 1998 SECCIÓN 3.6.1:

Si el control llega al final de los principales sin encontrar una declaración de retorno, el efecto es el de ejecutar la devolución 0;

Todas las versiones de ambas normas desde entonces (C99 y C ++ 98) han mantenido la misma idea. Confiamos en las funciones miembro generadas automáticamente en C ++, y pocas personas escriben las declaraciones explícitas normal.py4 al final de una función normal.py5 . Las razones contra omitir parecen hervir hasta " Se ve raro ". Si, como yo, tiene curiosidad por el fundamento para el cambio en el CAMBIO A EL COMENTORIO DE C Lea esta pregunta . También tenga en cuenta que a principios de la década de 1990, esto se consideró "práctica descuidada" porque era un comportamiento indefinido (aunque ampliamente apoyado) en ese momento.

Así que le abojo omitiéndolo; Otros no están de acuerdo (¡a menudo vehementemente!) En cualquier caso, si encuentra un código que lo omite, sabrá que está explícitamente apoyado por el estándar y sabrá lo que significa.

Resultados

Aquí hay una versión reelaborada de su programa que incorpora todas estas sugerencias:

  normal.py6  

Algunas notas

El código revisado incluye dos variables normal.py7 . Esto significa que se inicializan en el tiempo de compilación y no cambian durante el curso del programa. Además, cada función de la invocación del normal.py8 tiene esas variables establecidas en los S exactamente Yo valores. La ventaja es que el compilador puede convertir esto en un código muy eficiente que requiere poca o ninguna ejecución de tiempo de ejecución y tamaño mínimo de código.

El normal.py9 Simplemente apunta a la primera etiqueta rm.c0 primero, y luego pasa a través de las etiquetas en rm.c1 hasta que encuentre rm.c2 En qué punto la rutina terminará si hay más delimitadores en la cadena de entrada.

Finalmente, recomendaría crear un código de prueba que ejecute una serie de casos de prueba y compara la salida real a la salida deseada. Al crear dicho programa de prueba, puede estar seguro de que si cambia el programa más tarde (por ejemplo, para más eficiencia o para agregar funciones adicionales), podrá asegurarse de que la función aún funciona según lo previsto y que no haya un comportamiento nuevo no deseado ( ¡Los errores!) Se han introducido.

Ejecución de la muestra

./ Splitter Foo: Bar Toes: 10 Edward: NoColon Two: Polones: aquí ::: Smoo

  rm.c3  

 

I see some things that may help you improve your program.

Break up the code into smaller functions

This is a very short program, so it's not critical here, but generally, rather than having everything in the main() function, it would be easier to read and maintain if each discrete step were its own function. For instance, I'd separate out the token splitting function so that main looks like this:

int main(int argc, char **argv) {     for (int i = 1; i < argc; i++) {         split(argv[i]);     } } 

Eliminate work that does not need to be done

The final j = 0 has no practical effect and should be eliminated. Think carefully about what your program is doing so that you don't have the computer do more work than is necessary.

Eliminate "magic numbers"

The code is mostly free of "magic numbers' (that is, hard-coded values for which there is no obvious meaning), but I'd suggest that it would make sense to have the delimter string be an assigned variable.

Use a for loop instead of while

Because both pt and the j variables are only used within the while loop, consider again reducing scope and turning that into a for loop with one of those variables.

Use a single call to printf where practical

Instead of calling printf twice for each parsed value, it would simplify the program to simply call printf once instead of twice.

Sanitize user input better

The code doesn't quite work as posted, as you apparently already know. It doesn't really take much more time or code to make the program not crash with malformed input, so I would strongly suggest doing so to make your program robust.

Omit return 0

When a C or C++ program reaches the end of main the compiler will automatically generate code to return 0, so there is no need to put return 0; explicitly at the end of main.

Note: when I make this suggestion, it's almost invariably followed by one of two kinds of comments: "I didn't know that." or "That's bad advice!" My rationale is that it's safe and useful to rely on compiler behavior explicitly supported by the standard. For C, since C99; see ISO/IEC 9899:1999 section 5.1.2.2.3:

[...] a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0.

For C++, since the first standard in 1998; see ISO/IEC 14882:1998 section 3.6.1:

If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;

All versions of both standards since then (C99 and C++98) have maintained the same idea. We rely on automatically generated member functions in C++, and few people write explicit return; statements at the end of a void function. Reasons against omitting seem to boil down to "it looks weird". If, like me, you're curious about the rationale for the change to the C standard read this question. Also note that in the early 1990s this was considered "sloppy practice" because it was undefined behavior (although widely supported) at the time.

So I advocate omitting it; others disagree (often vehemently!) In any case, if you encounter code that omits it, you'll know that it's explicitly supported by the standard and you'll know what it means.

Results

Here's a reworked version of your program incorporating all of these suggestions:

#include <stdio.h> #include <string.h>  void split(char *arg) {     static const char* label[] = { "item", "quantity", NULL };     static const char *delim = ":";     const char **lbl = label;     for (char *pt = strtok(arg, delim); pt != NULL && *lbl != NULL; ++lbl) {         printf("\t%s: %s\n", *lbl, pt);         pt = strtok(NULL, delim);     } }  int main(int argc, char **argv) {     for (int i = 1; i < argc; i++) {         printf("\nInput: %s\nOutput:\n", argv[i]);         split(argv[i]);     } } 

Some notes

The revised code includes two static const variables. This means that they are initialized at compile time and do not change during the course of the program. Further, every invocation of the split function has those variables set to the exact same values. The advantage is that the compiler can turn this into very efficient code requiring little or no runtime execution and minimal code size.

The lbl variable simply points to the first label "item" first, and then steps through the labels in label until it encounters NULL at which point the routine will end whether or not there are more delimiters in the input string.

Finally, I'd recommend creating test code that runs a number of test cases and compares the actual output to the desired output. By creating such a test program, you can be assured that if you change the program later (e.g. for more efficiency or to add additional features), you will be able to assure that the function still operates as intended and that no new unintended behavior (bugs!) have been introduced.

Sample run

./splitter foo:bar toes:10 Edward: nocolon two:colons:here :: : smoo

Input: foo:bar Output:         item: foo         quantity: bar  Input: toes:10 Output:         item: toes         quantity: 10  Input: Edward: Output:         item: Edward  Input: nocolon Output:         item: nocolon  Input: two:colons:here Output:         item: two         quantity: colons  Input: :: Output:  Input: : Output:  Input: smoo Output:         item: smoo 
 
 
   
   

Relacionados problema

1  Compruebe si dos cadenas son permutación entre sí  ( Check if two strings are permutation of each other ) 
private String sort(String word) { char[] content = word.toCharArray(); Arrays.sort(content); return new String(content); } private boolea...

11  Optimizando el corrector de anagramas Java (comparar 2 cadenas)  ( Optimizing java anagram checker compare 2 strings ) 
Un anagrama es como una mezcla de las letras en una cadena: pots es un anagrama de detener wilma es un anagrama de ilwma Estoy pasando por el ...

1  Imprima todos los tamaños posibles de subsecuencias de cadena en C  ( Print out all possible sizes of subsequences of string in c ) 
Por ejemplo, dada una cadena "abcdefghijk", quiero que mi función se imprima: a, b, c, d, e, f, g, h, i, j, k. ab, bc, cd, de, ef, fg, gh, hi, ij, jk ab...

3  Implementación más portátil de Tolower ()  ( More portable tolower implementation ) 
Me estoy desafiando a intentar intentar escribir una función que sea tan eficiente, portátil y a prueba de fallas posible. La función es muy simple y solo con...

10  Función recursiva que genera las permutaciones de una cadena  ( Recursive function that generates the permutations of a string ) 
Estoy buscando una revisión de mi función recursiva que genere las permutaciones de una cadena. ¿Hay mejores formas de hacer esto? var permutations = []; ...

8  Conversión de STD :: Chrono :: Time_Point to / from std :: string  ( Converting stdchronotime point to from stdstring ) 
Considere estas funciones que permitan convertir checkOnline.sh4 a / FROM checkOnline.sh5 Con un formato Fecha de fecha ". checkOnline.sh6 con uso:...

2  Función para borrar un carácter en una cadena  ( Function to erase a character in a string ) 
void chrrem (char arr[], size_t len, size_t pos) { memmove(arr + pos, arr + (pos + 1), (len - pos) + 1); } Se supone que es simplemente rápido. Borra...

9  Convierta una contraseña a una cadena fonética para usuarios finales  ( Convert a password to a phonetic string for end users ) 
Tanto como lo odio, a veces proporcionar contraseñas a las personas debe hacerse electrónicamente. Cuando hago eso, trato de eliminar cualquier ambigüedad que...

18  Invirtiendo una cadena  ( Reversing a string ) 
Tuve esto como una pregunta de entrevista, y el entrevistador señaló esto. Esto es lo que escribí: //C# Syntax here public string Reverse(string s) { c...

6  Las vocales en una cadena están en orden alfabético  ( Vowels in a string are in alphabetical order ) 
Tarea Escriba una implementación que devuelva si un 99887776655544330 tiene vocales (idioma inglés) en orden alfabético (A-Z) o no. Feedback es mi v...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos