2012-09-11 13 views
5

Estoy intentando recrear los comandos head, y tail de linux para mi clase de programación. Acabamos de empezar a usar C, por lo que soy nuevo en la idea de asignar memoria y punteros. Me pregunto por qué esto no funciona.C Basic Head Command

#include <stdio.h> 
#include <stdlib.h> 

int main(int argc,char **argv){ 

    /* Checks if correct amount of arguements */ 

    if(argc != 2 || argc != 4){ 
     printf("Usage: %s head <file> \n Or: head <file> -n <number of characters>", argv[0]); 
     exit(-1); 
    } 

    if(strcmp(argv[1], "-n" != 0)){ 
     char fileName[strlen(argv[1])] = argv[1]; 
    } 
} 

//Compile error on char fileName[strlen(argv[1])] = argv[1]; 

Cualquier información adicional también sería útil.

+1

'fileName' también solo es visible dentro de su bloque delimitador, en este caso la rama afirmativa de la instrucción' if'. – gcbenison

+2

Solo verá el mensaje de uso, porque si 'argc' es igual a 2, no es igual a 4, y si es igual a 4, no es igual a 2, y si no lo es 2 ni 4, entonces ... –

+0

¿Especificó '-std = c99' en la línea de comando de GCC? Aún debe hacer eso para que el compilador acepte un VLA (matriz de longitud variable). –

Respuesta

2

Lo primero es lo primero, su uso no coincide con la comprobación de sus argumentos. De acuerdo con el uso, se debe utilizar uno de:

head <filename> 
head <filename> -n <count> 

En otras palabras, es argv[1] siempre el nombre del archivo, argv[2] es la que se debe establecer a -n si hay más de dos argumentos.

En segundo lugar, a menos que desee utilizar Vlas (arrays de longitud variable), probablemente debería simplemente establecer un puntero al nombre de fichero con algo como:

char *fileName = argv[1]; 

No es necesario cambiarlo a todo (probablemente lo pasará al fopen, presumiblemente), por lo que es una pérdida tratar de hacer otra copia.

Además, su declaración if es incorrecta como or, debería ser and. Está garantizado que argc no será 2 o no será 4, ya que no puede ser ambos al mismo tiempo.

Me gustaría empezar con algo como:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

static int usage (void) { 
    printf ("Usage: head <file>\n"); 
    printf (" or: head <file> -n <number of characters>\n"); 
    return -1; 
} 

int main (int argc,char *argv[]) { 
    char *fileName; 
    int lineCount; 

    // Checks if correct arguments 

    if ((argc != 2) && (argc != 4)) return usage(); 

    if ((argc == 4) && (strcmp(argv[2], "-n" != 0)) return usage(); 

    // Get file spec and line count 

    fileName = argv[1]; 

    lineCount = (argc == 2) ? 10 : atoi (argv[3]); // or strtol for purists 
    if (linecount < 0) lineCount = 0; 

    // Now go ahead and implement the logic for head. 

} 
+0

y tenga en cuenta que con este enfoque 'fileName' es _not_ una copia profunda de argv [1] - es solo un puntero que comparte su contenido con argv [1]. Esto está bien ya que argv [] usualmente no se desasigna. En otras situaciones, este es uno de los "errores" de C. – gcbenison

+2

"Normalmente" nunca desasignado? Diría "nunca", al menos no hasta después de que 'main' regrese (o tu programa sale de alguna otra forma). – paxdiablo

3

Creo que es mejor escribir:

char fileName[strlen(argv[1])+1]; 
strcpy(fileName, argv[1]); 

o (si no whant para hacer una copia de cadena):

char* fileName = argv[1]; 
+2

No tiene sentido hacer una copia de un argumento a menos que vaya a modificar la copia, por lo que su segunda sugerencia es mucho más sensata. –

+0

Depende de la situación ¿no es así? El autor intentó hacer una copia por algún motivo, por lo tanto, puede ser que lo haya hecho con un propósito y quiera modificar esta cadena en algún lugar ... – Tutankhamen

+0

En el código de 'head', el uso más plausible para el nombre de archivo es abrir y, para eso, no necesita la copia (el original debería hacerlo). Tiene razón en que, en algunas circunstancias, es necesario copiar y editar el nombre. Por ejemplo, si tiene algún tipo de 'compilador', puede querer cambiar la extensión del archivo de entrada para especificar el archivo de salida.Si es así, hacer una copia de toda la cadena y editar la copia es una buena idea porque también necesita el nombre del archivo de entrada para cosas como la llamada abierta y el informe de errores. –