(C) 构建结构体指针时,字符指针成员被无意中替换为“�”

问题描述 投票:0回答:1

我正在用 C 语言构建一个命令行解析器,我在其中获取命令行输入并将其组织成一个结构体。该结构有一个命令成员,该成员包含一个结构,该结构具有第一个命令、其参数以及指向下一个命令结构的指针成员,依此类推。命令和相应的参数在输入字符串中由竖线分隔。每个命令结构体都有一个名为 command_args 的成员 char* 数组,它保存命令和所有参数。

我的函数在大多数情况下似乎都能正常工作,但在某些奇怪的情况下,命令将被替换为看似随机的字符串。我注意到它似乎不会在第一个命令中发生,并且仅在有多个参数时才会发生。使用调试器,我注意到,首先,命令被正确插入到结构中,但后来当函数到达第二个参数时,参数被正确插入到结构位置,但同时用不同的值替换命令。我注意到它似乎永远不会在第一个命令中发生(仅在后续命令中),并且仅在有多个参数时发生。

我已经包含了 .c 和 .h 文件以及输出示例,任何有关如何修复错误的帮助将不胜感激。

myshell_parser.c

#ifndef MYSHELL_PARSER_H
#define MYSHELL_PARSER_H
#include <stdbool.h>

#define MAX_LINE_LENGTH 512
#define MAX_ARGV_LENGTH (MAX_LINE_LENGTH / 2 + 1)

struct pipeline_command {
  char *command_args[MAX_ARGV_LENGTH]; // arg[0] is command, rest are arguments
  char *redirect_in_path;  // NULL or Name of file to redirect in from 
  char *redirect_out_path; // NULL or Name of a file to redirect out to
  struct pipeline_command *next; // next command in the pipeline. NULL if done 
};

struct pipeline {
  struct pipeline_command *commands; // first command
  bool is_background; // TRUE if should execue in background
};

void pipeline_free(struct pipeline *pipeline);

struct pipeline *pipeline_build(const char *command_line);

#endif /* MYSHELL_PARSER_H */

myshell_parser.c

#include "myshell_parser.h"
#include "stddef.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct pipeline *pipeline_build(const char *command_line)
{
  struct pipeline_command* current;
  current = malloc(sizeof(struct pipeline_command));
  
  struct pipeline* output;
  output = malloc(sizeof(struct pipeline));
  output->is_background = 0;
  output->commands = current;
  
    
  char currentStr[100] = "";
  int argCount = 0;
  bool redirOut = 0;
  bool redirIn = 0;
  bool strFin = 0;
  
  for(int i = 0; command_line[i] != 0; i++)
  {
    if(command_line[i] == '&')
    {
      output->is_background = 1;
    }
    
    if(command_line[i] != ' ' && command_line[i] != '|' && command_line[i] != '<' && command_line[i] != '>' && command_line[i] != '\n' && command_line[i] != '&')
    {
      strFin = 0;
      char temp[2];
      temp[0] = command_line[i];
      temp[1] = 0;
      strcat(currentStr, temp);
    }

    
    if(((command_line[i+1] != ' ' && command_line[i] == ' ') || command_line[i] == '|' || command_line[i] == '\n' || command_line[i + 1] == 0 || command_line[i] == '<' || command_line[i] == '>' || command_line[i] == '&') && currentStr[0] != 0)
    {
      strFin = 1;
    }
    
    if(strFin)
    {      
      if(currentStr[0] == 0)
      {
    continue;
      }
      
      if(!redirOut && !redirIn)
      {
    current->command_args[argCount] = strdup(currentStr);
    strFin = 0;
    argCount++;
    //currentStr.clear();
    currentStr[0] = 0;
      }
      else if(redirOut)
      {
    current->redirect_out_path = strdup(currentStr);
    currentStr[0] = 0;
    redirOut = 0;
    strFin = 0;
      }
      else if(redirIn)
      {
    current->redirect_in_path = strdup(currentStr);
    currentStr[0] = 0;
    redirIn = 0;
    strFin = 0;
      }
      

    }
    if(command_line[i] == '|')
    {
      argCount = 0;
      struct pipeline_command* nextc;
      nextc = malloc(sizeof(struct pipeline));
      current->next = nextc;
      current = nextc;

    }
    else if(command_line[i] == '>')
    {
      redirOut = 1;
      argCount = 0;
    }
    else if(command_line[i] == '<')
    {
      redirIn = 1;
      argCount = 0;
    }
  }
  
  //  printf("out: %s\n", output->commands->next->command_args[0]);
    // TODO: Implement this function
    return output;
}
void pipeline_free(struct pipeline *pipeline)
{
  struct pipeline_command* current = pipeline->commands;
  struct pipeline_command* temp = current;
  while(current != NULL){
    temp = current;
    current = current->next;
    for(int i = 0; temp->command_args[i] != NULL; i++)
    {
      free(temp->command_args[i]);
      free(temp->redirect_in_path);
      free(temp->redirect_out_path);
    }
    free(temp);
    
  }

  free(pipeline);
    // TODO: Implement this function
}

输入:

struct pipeline *my_pipeline = pipeline_build("cat arg1 arg2 arg3 < input.txt | grep arg1 arg2 arg3 | ls arg1 arg2 arg3 > Output.txt &");

输出:

mypipeline->commands->next->command_args[0] 返回“�”而不是“grep”

mypipeline->commands->next->next->command_args[0] 返回“�”而不是“ls”

但是,mypipeline->commands->command_args[0]按预期返回“cat”

c pointers struct char char-pointer
1个回答
0
投票

您的代码具有未定义的行为,因为您尝试分配太小的内存块。结果,您写入了您无权访问的内存,任何事情都可能发生。

我们来看看这部分代码。

    if(command_line[i] == '|')
    {
      argCount = 0;
      struct pipeline_command* nextc;
      nextc = malloc(sizeof(struct pipeline));
      current->next = nextc;
      current = nextc;

    }

malloc
的内存大小为
struct pipeline
,但你的指针是
struct pipeline_command
类型。例如,在使用 gcc 的 x86_64 上,
sizeof(struct pipeline)
为 16,而
sizeof(struct pipeline_command)
为 2080,
offsetof(struct pipeline_command, next)
为 2072,因此您已经在下一行中访问无效内存。

为了避免此类错误,您可以直接将

sizeof
运算符与表达式而不是类型一起使用。

改变

nextc = malloc(sizeof(struct pipeline));

nextc = malloc(sizeof *nextc);
© www.soinside.com 2019 - 2024. All rights reserved.