我正在学习UNIX系统编程。我正在为UNIX编写一个简单的shell应用程序(我在OS X Yosemite ver 10.10.5上使用Xcode)。我对C有过一些经验,但并不多。
实用程序工作正常并将打印unicode字符(虽然在Xcode控制台中打印' ????'而不是它,但它似乎是调试器本身的问题)。
我进行了一些研究,发现strcmp()
也可以正常工作,只要它只是比较字节并最终查找零字节。读取输入也应该没问题,因为你只是读取字节。
我还读到unicode字符串不应该包含空字节。但是,在执行`strcmp()时,某些输入将导致EXC_BAD_ACCESS
。
代码:
阅读用户输入:
char* readCommand(void) {
int buffer_size = LINE_BUFFER_SIZE;
char *buffer = malloc(sizeof(char) * buffer_size);
int position = 0;
int character;
if(!buffer)
{
fprintf(stderr, "readCommand failed: memory allocation error");
exit(ALLOCATION_ERROR);
}
while (1) {
character = getchar();
if(character == EOF || character == '\n')
{
buffer[position] = '\0';
char* cmd = buffer;
free(buffer);
return cmd;
}
else {
buffer[position] = character;
}
if(++position >= sizeof(buffer))
{
buffer_size += LINE_BUFFER_SIZE;
buffer = realloc(buffer, sizeof(char) * buffer_size);
if(!buffer) {
fprintf(stderr, "readCommand failed: memory reallocation error");
free(buffer);
exit(ALLOCATION_ERROR);
}
}
}
return NULL;
}
分裂args:
int split_string_quotes(char* source, char** argv, size_t arg_count)
{
enum split_states state = DULL;
char* p, *word_start = NULL;
int character;
int argc = 0;
for(p = source; argc < arg_count && *p != '\0'; p++)
{
character = (unsigned char) *p;
switch (state) {
case DULL:
if(isspace(character))
{
continue;
}
if(character == '"')
{
state = IN_STRING;
word_start = p+1;
continue;
}
state = IN_WORD;
word_start = p;
continue;
case IN_WORD:
if(isspace(character))
{
state = DULL;
*p = 0;
argv[argc++] = word_start;
}
continue;
case IN_STRING:
if(character == '"')
{
state = DULL;
*p = 0;
argv[argc++] = word_start;
}
continue;
}
}
if(state != DULL && argc < arg_count)
{
argv[argc++] = word_start;
}
argv[argc] = NULL;
return argc;
}
strcmp所在的地方:
int shell_execute(char **args)
{
for(int i = 0; i < 3; i++)
{
if(strcmp(args[0], commands[i]) == 0)
{
return (*standardFuncs[i])(args);
}
}
shell_launch(args);
return 0;
}
主循环
char* current_dir = malloc(sizeof(char)*PATH_MAX);
char* args[MAX_ARGS];
char* command;
printf("dolphinShell (c) Alex Kale 2016\n");
while (1)
{
getwd(current_dir);
printf("dsh: %s-> ", current_dir);
command = readCommand();
printf("%s\n", command);
split_string_quotes(command, args, MAX_ARGS);
if(shell_execute(args) == -1) break;
}
free(current_dir);
return 0;
所以,问题是我输入的一些unicode字符串工作正常并且永远不会导致EXC_BAD_ACCESS
,但是当我输入фывпфвыапы
时,它会中断。我认为问题在于访问args[0]
,但这是调试器的输出:
Printing description of args:
(char **) args = 0x00007fff5fbff900
*args char * 0x101800a00 0x0000000101800a00
Printing description of *(*(args)):
(char) **args = '\xd1'
所以它认为args[0]
是空的,但它是空的吗?或者它被所有零混淆了吗?
我真的很困惑,我花了很多时间研究,似乎被困在这里。
我也尝试过使用wchar_t
和wcscmp()
,但它与execvp()
无关,并且无法解决问题。
我也尝试了gcc -Wall -Wextra
,输出结果如下:
main.c:53:26: warning: comparison of integers of different signs: 'int' and
'size_t' (aka 'unsigned long') [-Wsign-compare]
for(p = source; argc < arg_count && *p != '\0'; p++)
~~~~ ^ ~~~~~~~~~
main.c:92:30: warning: comparison of integers of different signs: 'int' and
'size_t' (aka 'unsigned long') [-Wsign-compare]
if(state != DULL && argc < arg_count)
~~~~ ^ ~~~~~~~~~
main.c:124:23: warning: comparison of integers of different signs: 'int' and
'unsigned long' [-Wsign-compare]
if(++position >= sizeof(buffer))
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
main.c:180:18: warning: unused parameter 'args' [-Wunused-parameter]
int dHelp(char **args)
^
main.c:203:18: warning: unused parameter 'args' [-Wunused-parameter]
int dExit(char **args)
^
main.c:210:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, const char** argv)
^
main.c:210:33: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, const char** argv)
^
7 warnings generated.
但我认为不是这样(如果我错了,请纠正我)。
答案 0 :(得分:2)
显示的代码中存在多个错误。
func performUpdateControl(){
let reach = Reachability.reachabilityForInternetConnection()!
if reach.isReachable() {
work.getData()
} else {
UIAlertView(title: "Device without connection", message: "You must have an internet connection to use this feature", delegate: nil, cancelButtonTitle: "OK").show()
}
//add this
NSNotificationCenter.defaultCenter().postNotificationName("refreshCompleted", object: nil)
}
返回指向已删除 char* cmd = buffer;
free(buffer);
return cmd;
缓冲区的指针。继续使用此指针会导致未定义的行为。
char
if(++position >= sizeof(buffer))
是buffer
。这相当于:
char *
这将是4或8个字节,具体取决于您的硬件平台。每当缓冲区大于4或8字节时,就会不必要地调整缓冲区的大小。
您似乎相信 if(++position >= sizeof(char *))
给出了sizeof()
- ed缓冲区的大小。它没有。
总之:您的总体方法是编写一大堆代码,然后尝试查看它是否正常工作。这是错误的做法。你需要编写一个小函数。例如将一行读入缓冲区的那个。测试一下。验证它是否有效。现在您知道它可行了,继续前进并编写整个程序的下一个小部分。
答案 1 :(得分:0)
代码中的一个巨大错误就是您阅读输入的方式。看看这部分:
if(character == EOF || character == '\n')
{
buffer[position] = '\0';
char* cmd = buffer;
free(buffer);
return cmd;
}
在这里,您正在使用nil终止buffer
,正如您所希望的那样。然后指定cmd
指向与buffer
相同的内存,释放缓冲区并将指针返回到已释放的内存。如果在此之后您使用返回的指针,则不允许任何事情发生任何事情。记忆可以在某个地方重复使用,你可以获得访问权限,也可能是你附近的火山爆发。
指定另一个变量的指针并不能复制内存,只是让它们指向同一个地方。在停止使用内容之前,您无法释放内存。这很可能会导致您的问题。