从 windows 和 mac 通过 ssh 编译和运行 C 程序 -- windows 出现 seg 错误

标签 c linux macos segmentation-fault

所以我有一个特定的 C 程序,当我编译和运行时,它可以在我的 Mac 上运行。我还在学校的linux计算机上通过ssh进行了测试,运行良好。然而,我的 friend 有一台PC,他使用PuTTY访问Linux计算机,并且使用完全相同的代码,他在运行程序时总是出现段错误。为什么会这样?

下面列出了代码。我已经提供了完整的代码,但是正如我们通过 print 语句发现的那样,问题在于主 block 早期的 int counter = 0; 行:

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

typedef struct Nodes{
    char firstName[40];
    char lastName[40];
    char townName[70];
    struct Nodes* next;
} Node;

//-- create head global variable.
Node* head;

//-- check if a char array contains a dash (to check for the 9 digit zip code)
bool containsDash(char* string){
    char *s;
    s = strchr (string, '-');
    if (s==NULL){
        return false;
    }
    else{
        return true;
    }
}

//-- insert node after ptr, with given attributes.
void insertNodeAfter(Node* ptr, char* fName, char* lName, char* tName){
    Node* newPtr = (Node*) malloc(sizeof(Node));
    strcpy(newPtr->firstName, fName);
    strcpy(newPtr->lastName, lName);
    strcpy(newPtr->townName, tName);
    newPtr->next = ptr->next;
    ptr->next = newPtr;
}

//-- insert node before head.
Node* insertNodeBeforeHead(char* fName, char* lName, char* tName){
    Node* ptr = (Node*) malloc(sizeof(Node));
    strcpy(ptr->firstName, fName);
    strcpy(ptr->lastName, lName);
    strcpy(ptr->townName, tName);

    ptr->next = head;
    head = ptr;
    return ptr;
}

//-- check if char array starts with start
bool startsWith(char *start, char *str){
    size_t lenstart = strlen(start);
    size_t lenstr = strlen(str);
    if (lenstart > lenstr){
        return false;
    }
    else{
        return strncmp(start, str, lenstart) == 0;
    }
}

//-- check if nodes have equal attributes.
bool nodesEqual(Node* first, Node* second){
    if (strcmp(first->firstName, second->firstName) == 0 && strcmp(first->lastName, second->lastName) == 0 && strcmp(first->townName, second->townName) == 0){
        return true;
    }
    else{
        return false;
    }
}

//-- delete ptr node
void deleteNode(Node* ptr){
    if (nodesEqual(ptr, head)){
        head = ptr->next;
        free(ptr);
    }
    else{
        Node* temp = head;
        while(1){
            if (nodesEqual(temp->next, ptr)){
                temp->next = temp->next->next;
                free(ptr);
                break;
            }   
            else{
                temp = temp->next;
            }
        }
    }
}

//-- delete node with the given first and last name
void deleteNodeByInfo(char* fName, char* lName){
    if (head == NULL){
        return;
    }
    Node* temp = head;
    while(1){
        if (strcmp(temp->firstName, fName) == 0 && strcmp(temp->lastName, lName) == 0){
            deleteNode(temp);
            break;
        }
        if (temp->next != NULL){
            temp = temp->next;
        }
        else{
            break;
        }
    }
}

//-- take the current attributes and make a node in the correct spot
void insertNodeInCorrectSpot(char* fName, char* lName, char* tName){
    //-- take 2 pointers separated by one link, look for a spot to insert node between these pointers
    Node* pointer = head;
    Node* pointer2 = head;
    if (pointer->next != NULL){
        pointer2 = pointer2->next;
    }
    else{
        pointer2 = pointer2->next;
    }
    if (strcmp(tName, pointer->townName) < 0){
        Node* newHead = insertNodeBeforeHead(fName, lName, tName);
        head = newHead;
    }
    else{
        while(strcmp(tName, pointer2->townName) > 0){
            if (pointer2->next != NULL){
                pointer = pointer->next;
                pointer2 = pointer2->next;
            }
            else{
                pointer = pointer2;
                break;
            }
        }
        insertNodeAfter(pointer, fName, lName, tName);
    }
}

//-- remove spaces at the end of a string
void removeSpacesAtEnd(char* input){
    int end = strlen(input) - 1;
    if (isspace(input[end])){
        input[end] = '\0';
    }
    if (isspace(input[--end])){
        removeSpacesAtEnd(input);
    }
}

//-- print the attributes of a given node
void printNode(Node* pointer){
    printf("%s", pointer->firstName);
    // printf("%s", " ");
    printf("%s", pointer->lastName);
    // printf("%s", " ");
    printf("%s\n", pointer->townName);
}

// -d is option for debug.

int main(int argc, char* argv[]){
    int counter = 0; //-- keep counter to keep track of cycle
    char *tempChar, *tempFName, *tempLName, *tempTName;

    //-- create buffers to store first name, last name, town name
    tempChar = (char*)malloc(100*sizeof(char));
    tempFName = (char*)malloc(40*sizeof(char));
    tempLName = (char*)malloc(40*sizeof(char));
    tempTName = (char*)malloc(70*sizeof(char));
    while(counter < 600){
        fgets(tempChar, 100, stdin);
        //-- remove newline delimiter
        char *pos;
        if ((pos=strchr(tempChar, '\n')) != NULL)
            *pos = '\0';
        //-- The text will always go in a cycle of 6. Use modular division to figure out what is in the line being read.
        if (counter % 6 == 0){
            strncpy(tempFName, tempChar, strlen(tempChar));
            removeSpacesAtEnd(tempFName);
            strcat(tempFName, " ");
        }
        else if (counter % 6 == 1){
            strncpy(tempLName, tempChar, strlen(tempChar));
            removeSpacesAtEnd(tempLName);
            if (counter == 1){
                size_t len = strlen(tempChar);
                tempLName[len] = '\0';
            }
            strcat(tempLName, " ");
        }
        else if (counter % 6 == 3){
            if (containsDash(tempChar)){
                strncpy(tempTName, tempChar, strlen(tempChar)-15);
            }
            else{
                strncpy(tempTName, tempChar, strlen(tempChar)-9);
            }
            removeSpacesAtEnd(tempTName);
            strcat(tempTName, " ");
        }
        else if (counter % 6 == 4){
            if (counter == 4){
                head = (Node*) malloc(sizeof(Node));
                strcpy(head->firstName, tempFName);
                strcpy(head->lastName, tempLName);
                strcpy(head->townName, tempTName);
            }
            else{
                insertNodeInCorrectSpot(tempFName, tempLName, tempTName);
            }
            memset(tempFName, 0, strlen(tempFName));
            memset(tempLName, 0, strlen(tempLName));
            memset(tempTName, 0, strlen(tempTName));
        }
        memset(tempChar, 0, strlen(tempChar));
        counter++;
    }
}

最佳答案

我不知道这是否是你 friend 遇到的同样的问题。但是在添加了 stdbool.h 后,我可以通过像这样运行它来在我的 mac 上获得段错误:

$ ./testit < /etc/group

这里出了问题:

//-- remove spaces at the end of a string
void removeSpacesAtEnd(char* input){
    int end = strlen(input) - 1;
    if (isspace(input[end])){
        input[end] = '\0';
    }
    if (isspace(input[--end])){
        removeSpacesAtEnd(input);
    }
}

输入错误:

"# Note that this file is consulted directly only when the system i"

该行倒数第二个位置包含空格,但最后一个位置不包含空格。这会导致 removeSpacesAtEnd() 函数无限递归,直到填满调用堆栈。

最简单的修复方法是将第二个“if” block 移到第一个“if” block 内,这样它仅在输入的最后一个字符是空格时执行:

//-- remove spaces at the end of a string
void removeSpacesAtEnd(char* input){
    int end = strlen(input) - 1;
    if (isspace(input[end])){
        input[end] = '\0';
        if (isspace(input[--end])){
            removeSpacesAtEnd(input);
        }
    }
}

修复该问题后,程序现在在这里崩溃:

    else if (counter % 6 == 3){
        if (containsDash(tempChar)){
            strncpy(tempTName, tempChar, strlen(tempChar)-15);
        }
        else{
            strncpy(tempTName, tempChar, strlen(tempChar)-9); <-- Here
        }

所以,这个程序可能还有其他问题。

您应该学习如何使用调试器。这真的不难,而且会节省你很多令人沮丧的时间。以下是我如何使用 OSX 调试器 lldb 来找出第二次崩溃:

使用调试符号(-g)编译程序:

$ gcc -g -o testit testit.c
$

在“testit”程序上调用调试器。在 Linux 上,您可以使用 gdb 而不是 lldb,但我将在此处使用的命令是相同的。

$ lldb testit
(lldb) target create "testit"
Current executable set to 'testit' (x86_64).
(lldb)

运行“testit

(lldb) run < /etc/group
Process 40951 launched: '/Users/kherron/x/testit' (x86_64)
Process 40951 stopped
* thread #1: tid = 0xc882f9, 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100200000)
    frame #0: 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41
libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown:
->  0x7fff8bde3c69 <+41>: rep    
    0x7fff8bde3c6a <+42>: stosb  %al, %es:(%rdi)
    0x7fff8bde3c6b <+43>: movq   %rdx, %rax
    0x7fff8bde3c6e <+46>: popq   %rbp
(lldb)

是的,这对我来说也是官样文章。别担心。让我们看看这里的函数调用堆栈。 “bt”是“backtrace”,打印调用堆栈。

(lldb) bt
* thread #1: tid = 0xc882f9, 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100200000)
  * frame #0: 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41
    frame #1: 0x00007fff8e90e40d libsystem_c.dylib`stpncpy + 70
    frame #2: 0x00007fff8e980f12 libsystem_c.dylib`__strncpy_chk + 38
    frame #3: 0x0000000100001c20 testit`main(argc=1, argv=0x00007fff5fbffb70) + 752 at testit.c:201
    frame #4: 0x00007fff8b56c5c9 libdyld.dylib`start + 1
(lldb)

第 3 帧看起来像程序中的一行。我们来看看。

(lldb) up 3
frame #3: 0x0000000100001c20 testit`main(argc=1, argv=0x00007fff5fbffb70) + 752 at testit.c:201
   198                  strncpy(tempTName, tempChar, strlen(tempChar)-15);
   199              }
   200              else{
-> 201                  strncpy(tempTName, tempChar, strlen(tempChar)-9);
   202              }
   203              removeSpacesAtEnd(tempTName);
   204              strcat(tempTName, " ");

好的,打印当时tempChar的值。

(lldb) p tempChar
(char *) $0 = 0x0000000100104b80 "##"

为了清楚地说明这一点,请打印出表达式“strlen(tempChar)-9”的值:

(lldb) p strlen(tempChar) - 9
error: 'strlen' has unknown return type; cast the call to its declared return type
error: 1 errors parsing expression
(lldb) p (int)(strlen(tempChar)) - 9
(int) $1 = -7

因此,它将负长度传递给 strlen()。

关于从 windows 和 mac 通过 ssh 编译和运行 C 程序 -- windows 出现 seg 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32547313/

相关文章:

linux - 将新文件上传到服务器时出现 500 内部错误

c - GArray 元素的可用内存

关闭终端实例后,JAVA_HOME 未设置/保存到路径变量

C 光标问题

c++ - 如何使用嵌套在没有名称的结构中的c union

c - 通过 C 中的指针将结构传递给函数

mysql - 无法在 OS X 上连接到 mysql

c - 简单的 OpenCL 程序编译并运行但输出不正确

linux - Linux源码编译问题

swift - 使用 Swift 禁用 OSX 的 sleep /屏幕保护程序