正确使用指针

时间:2016-11-28 17:43:29

标签: c shell pointers

我在使用C语言实现shell命令时遇到了问题。 我想这是因为我使用指针错误,因为我对这种语言很新。 现在,我正在研究“cd”和“export”命令。仅当我在代码中指定路径而不是在用户键入路径时,更改目录才有效。我很确定这是因为args[1]。我试图打印它,但报告了一个分段错误。出口报告相同,我认为这是因为“args”管理不善。 我做错了什么?

注意:我说西班牙语,但我没有翻译代码的某些部分,因为我认为它们仍然可以理解。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define PROMPT "$"
#define MAX_LINE 512


int parse_args(char **args, char *line){
    int n=0;
    char* token;
    char delimit[]=" \t\r\n\v\f";
    token=strtok(line,delimit);
    while(token!=NULL){
        printf("token%i: %s\n",n,token);
        args=token;
        n++;
        args++;
        token=strtok(NULL,delimit);
    }
    printf("token%i: %s\n",n,token);
    args=token;
    return n;
}

char *read_line(char *line){
    printf("%s%s ",getenv("USER"),PROMPT);
    fflush(stdout);
    line=fgets(line,MAX_LINE,stdin);
    return line;
}


int execute_line(char *line){
    char **args;
    parse_args(args,line);
    check_internal(args);
    return 0;
}

int check_internal(char **args){
    if( strcmp(args, "cd")==0 ){
        internal_cd();
    } else{
        if( strcmp(args, "export")==0 ){
            internal_export();
        }else{
            if( strcmp(args, "source")==0 ){
                internal_source();
            }else{
                if( strcmp(args, "jobs")==0 ){
                    internal_jobs();
                }else{

                    return 0;
                }
            }
        }
    }
}

int internal_cd(char **args){
    char buff[50];
    printf("Comando cd \n");
    char directorio []= "/home/jamengual1/Escritorio/FlashDRIVE";
    printf("%s", args+1);
    if (chdir(directorio) == -1){
        fprintf(stderr, "Error %d: %s\n", errno, strerror(errno));
        perror("Error");
        return -1;
    } else{
        printf("Estás en el directorio: %s \n", getcwd(buff, 50));
        return 1;
    }

}

   //doing it this way(which should be the right one) it reports a Bad Address error
/*int internal_cd(char **args){
    printf("%s","cambio de directorio\n");
    char buff[50];
    printf("Comando cd \n");
    //printf("%s", args[1]); //segmentation fault
    if (chdir(args[1]) == -1)
    {
        //fprintf(stderr, "Error %d: %s\n", errno,strerror(errno));
        perror("Error");
        return -1;
    }

    printf("Estás en el directorio: %s \n", getcwd(buff, 50));
    return 1;

}
*/

int internal_export(char **args) {
    printf("%s","éste es el export\n");
    char *variable;
    char *nuevo_valor;
    char *aux;

    variable = strtok(args[1], "=");
    nuevo_valor = strtok(NULL, args[1]);
    aux = getenv(variable);

    if((int)aux == -1)
    {
        perror("Error: getenv");
        return -1;
    }
        printf("VAR: '%s'. Valor: '%s'. Nuevo valor: '%s'\n", variable, aux, nuevo_valor);

    if(!nuevo_valor){
        perror("Error: error de sintaxis");
        return -1;

    }

        if ((setenv(variable,nuevo_valor,1)== -1))
        {

            perror("Error: llamada al sistema con setenv");
            return -1;

        }

        aux = getenv(variable);

        if((int)aux == -1)
        {
             perror("Error: llamada al sistema con getenv");
            return -1;

        }

        printf("Nuevo valor: '%s': '%s'\n", variable, aux);
        return 1;        

}



int internal_source(char **args) {
    printf("%s","éste es el source\n");
    return 1;
}

int internal_jobs(char **args){
    printf("%s","éste es el jobs\n");
    return 1;
}

void main(){
    char line[MAX_LINE]; 
    while(read_line(line)){
        execute_line(line);
    }
}

1 个答案:

答案 0 :(得分:3)

发布的代码有很多问题。我觉得OP实际上对学习很感兴趣,所以我想回答,但有很多回答要做,所以我将这个做成社区维基,希望其他人能够参与进来。

知道指针是什么

最大的问题是你在没有对他们有好感的情况下自由地使用指针。例如,行if((int)aux==-1)永远不会评估您想要的方式。 aux是char *,这意味着它是指向分配给一个或多个字符的内存区域的指针。 aux的值是一些任意数字 - 它是getenv结果的内存地址。它永远不会是-1;它更像是一个类似于0xdeadf00d的东西 - 只是一个存储位置的任意地址。但是,(在我的示例中),在0xdeadf00d,您可能有字符'-',在0xdeadf00e,您可能有字符'1',在0xdeadf00f,您可能有字符'\0' 。也就是说,指针指向的内存位置中的一系列字符将包含字符串&#34; -1&#34;。 (注意,字符串的结尾由一个设置为0的字节表示,这就是我们知道它结束的方式。当我们讨论你的args变量时,这个概念将变得很重要。)你不能将0xdeadf00d强制转换为int (它将是3735941133),并期望它与-1比较。

要使该行正常工作,您可以做两件事:您可以比较该位置的字符串,即使用if (strcmp(aux, "-1") == 0),或者您可以将aux转换为int,即{{1} }

始终知道指针指向的是什么。了解他们指向一个格式化为特定数据类型的内存区域。

那么什么是char **?

char **是指向包含一个或多个char *的内存区域的指针,char *是指向将包含一个或多个字符的内存区域的指针。在这种情况下,(atoi(aux) == -1)应该是&#34;字符串列表&#34;。创建一个args列表实际上是项目中最难的部分。您需要处理分配正确大小的内存,并处理您正在进行动态内存分配的事实。对于初学者来说,这些都是艰难的事情。

你所说的args的每一行都是非常错误的。正如您所提到的,它会产生不兼容类型的错误。您想将char *设置为char *。由于您可以将指针视为数组,因此args=token之类的内容将有效,但这会在同一位置重写每个令牌;你只获得最后一个令牌。你应该想要像args[0] = token这样的东西。但是存在一个问题 - args并没有指向任何东西!你需要为它分配空间! args本身应该是指向至少一个char *的内存位置,但它从未设置过。它通常使用args[n] = token设置。

我将推荐一种避免动态分配的方法。现在还有很多东西需要学习,而不需要处理分配和随后的内存泄漏风险;这至少会让你专注于指针。

malloc

我将其称为MAX_ARGC,因为在c中有一个约定,我们用一个该名称的变量跟踪arg列表中的参数数量。但这个名字并不重要。

请注意,我在最后添加了0。就像你终止一个&#34;字符串&#34;通过放置#define PROMPT "$" #define MAX_LINE 512 #define MAX_ARGC 128 char **args[MAX_ARGC] /* this defines args as a global char**, holding up to MAX_ARGC values */ int parse_args(char **args, char *line){ /* char **args is no longer necessary, since I made it global, but you can leave it */ int n=0; char* token; char delimit[]=" \t\r\n\v\f"; token=strtok(line,delimit); while(token!=NULL){ if (n>MAX_ARGC) { perror("Too many arguments") } printf("token%i: %s\n",n,token); args[n]=token; n++; token=strtok(NULL,delimit); } printf("token%i: %s\n",n,token); args[n] = NULL; return n; } 字符,您可以使用空指针终止指针列表。循环遍历列表时,在等于NULL时完成循环。 (这避免了argc的事情。)

这样做的动态方法是找出你有多少个参数,为末尾的NULL指针为那多个指针分配空间+ 1,然后将每个指针放入分配的空间。如果需要,您必须这样做;我提供的东西可以成为一个很好的垫脚石,所以你可以先控制你的指针。

其他事项

您可能在使用fgets的返回值'\0'时遇到问题。我相信大多数编译器都会让你逃脱它,但它是官方未定义的行为。我将其留了一天。

确保将args传递给internal_cd。