【问题标题】:I keep getting a segmentation fault and I'm not sure why我不断收到分段错误,我不知道为什么
【发布时间】:2019-02-28 09:09:21
【问题描述】:

我很确定这与我对 calloc() 的使用有关,但我不明白为什么。该程序的目标是让char* C 包含char* A 中不在char* B 中的字符。

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

char* diff(char* A, char*B);

int main() {
  char* A = {'q','g','e','\0'};
  char* B = {'a','d','e','\0'};
  char* C = diff(A,B);
  printf("%s", C);
  free(C);
  return(0);
}

int search(char* S, char c) {
    int i=0;

    while( S[i]!='\0' ){
        if( S[i]==c ) break;
        i++;
    }
    if( S[i]=='\0' ) return -1;
    else return i;
}

char* diff(char* A, char* B) {
    int i;
    char* C = calloc(strlen(A), sizeof(char));
    assert(C != NULL);
    int lengthC = 0;

    for (i = 0; i < strlen(A); i++) {
        if (-1 != -1) {
            C[lengthC] = A[i];
            lengthC++;
        }
    }

    C[lengthC] = '\0';
    return C;
}

【问题讨论】:

  • if (-1 != -1) 会是真的吗?
  • char* A = {'q','g','e','\0'}; 不起作用,你需要char A[] = { 'q','g','e','\0' };,当然B 也是如此。我在程序中没有看太多其他内容,但显然if (-1 != -1) 似乎很粗略。哦,你可以做return 0;。并不是说return(0); 破坏了任何东西,但它使它看起来像一个函数调用,而实际上并非如此。
  • 投票关闭是一个简单的错字,因为if (-1 != -1) 永远不会是真的,因此每个字符串都会在索引 0 处以空值终止。启用编译器警告。此外,您不会为新字符串中的空终止符分配空间。
  • @JeremyP OP 忽略 16 条编译器消息并转而询问互联网的问题在我的书中并不好,但无论如何......
  • 也没有分配足够的内存 - 你需要strlen(A)+1 这样你就有空间给'\0'

标签: c segmentation-fault dynamic-memory-allocation calloc


【解决方案1】:

char* 指针的初始化可能如下所示:

char *A = { (char*)(void*)(uintptr_t)5 };

这会将文字值5 分配为A 指针的值。 A 指针将(可能)指向无效的内存位置。

转换(char*)(void*)(uintptr_t)(或有点类似的转换)可能由编译器隐式完成。编译器最好至少发出一个关于从整数到指针的隐式转换的警告。

您还可以“超出”{ } 括号内的元素数量。即:

char* A = { 1, 2, 3, 4, 5, };

数字2, 3, 4, 5, 被忽略,因为char* 只能从一个值初始化。

编译器应该警告你这些,例如。在 gcc 中我得到:

<source>:6:16: warning: incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int' [-Wint-conversion]
    char* A = {'q','g','e','\0'};
               ^~~
<source>:6:20: warning: excess elements in scalar initializer
    char* A = {'q','g','e','\0'};

所以:

char* A = {'q','g','e','\0'};

等于:

char *A = 113;

根据ascii tableq 等于 113。

113 是无效指针。稍后在您的代码中执行:

strlen(A)

它试图访问A 指针后面的内存。由于指针无效,因此未定义会发生什么。在您的系统上,您会遇到分段错误。

A 变量可能应该变成一个数组:

char A[] = {'q','g','e','\0'};

或者等价的:

char A[] = "qge";

这将创建一个字符数组并用适当的值初始化它们。

【讨论】:

  • char* A = { 1, 2, 3, 4, 5, }; 不是有效的 C,因此无法编译。初始化器的数量错误,使用几个是 gnu poop 扩展而不是标准 C。还有一个约束冲突,因为你不能用 1 初始化 char*。问题只是 OP 没有读取编译器日志。
  • char* A = "ab"; 也可以。事实上,char *A = {'q','g','e','\0'}; 不起作用让我感到惊讶,因为当我学习 C 时(在 Ansi 之前的日子里)"ab" 被呈现为 { 'a', 'b', '\0'} 的语法糖。
  • @JeremyP 不,这是两种完全不同的情况。这不是数组初始化,而是标量(单项)初始化,因为我们有一个指针而不是数组。 char A[] = { ... } 可以正常工作。
  • @Lundin 在我的编译器上(Apple clang-1000.11.45.5)char* A = { 1, 2, 3, 4, 5, }; 确实可以编译,但它会针对初始化程序中的不兼容类型和多余元素发出警告。
  • @Lundin “这是两种完全不同的情况”。我知道他们是现在。这就是我评论的重点。
【解决方案2】:

您不能以这种方式初始化指针。 char* A = {'q','g','e','\0'}; 它可能似乎在某些编译器上编译,以这种方式初始化是错误的。 请记住,指针变量就像整数数据类型。它实际上包含一个包含内存位置地址的整数值。

相反,它应该作为数组被删除: 字符 A = {'q','g','e','\0'}; 数组名本身在 C 中表现为一个指针。(当然有一些限制),所以你将数组名本身作为参数传递给你的函数。

其次考虑您的程序目标:char* C 包含 char* A 中不在 char* B 中的字符,

语句 if(-1 != -1) 似乎是一个拼写错误,我猜你的意思是

如果 (搜索(B,A[i]) == -1)

在 calloc 调用时可能需要进行类型转换,因为它返回 void*

char* C = (char *) calloc(strlen(A), sizeof(char));

考虑到所有这些因素,以下程序将实现您的目标:

希望这会有所帮助:)

int main() {
    char A[] = { 'q','g','e','\0' };
    char B[] = { 'a','d','e','\0' };
    char* C = diff(A, B);
    printf("%s", C);
    free(C);
    return(0);
    }

int search(char* S, char c) {
    int i = 0;

    while (S[i] != '\0') {
        if (S[i] == c) break;
        i++;
        }
    if (S[i] == '\0') return -1;
    else return i;
}

char* diff(char* A, char* B) {
    int i;
    char* C = (char *) calloc(strlen(A), sizeof(char));
    assert(C != NULL);

    int lengthC = 0;

    for (i = 0; i < strlen(A); i++) {
        if (search(B,A[i]) == -1) {
            C[lengthC] = A[i];
            lengthC++;
        }
    }

    C[lengthC] = '\0';
    return C;
}

【讨论】:

  • 强制转换calloc的结果是没有意义的。而且您没有发现空终止符错误的缺失空间。它应该是char* C = malloc(strlen(A)+1);
猜你喜欢
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-24
  • 1970-01-01
  • 1970-01-01
  • 2017-05-07
  • 2017-11-23
相关资源
最近更新 更多