【问题标题】:Segmentation Fault with string array字符串数组的分段错误
【发布时间】:2010-11-30 16:15:00
【问题描述】:

我遇到了一些字符串数组问题,这些问题似乎侵犯了保留的内存空间。代码太大,这里就不贴了,所以我把重要的部分贴在下面:

int main (  ){

 int i = 0, j = 0, k = 0, count = 0, numLinhas = 0, l = 0;
 char string[100][100];
 char line [17];
 char str[4];
 char str1[5];
 char str2[4];
 char str3[4];

 FILE *p;
 p = fopen("text.txt", "r");
 while(fgets(line, sizeof line, p)!=NULL){
  printf("%s", line);
  strncpy(string[i], line, 17);
  i++;
  numLinhas++; 
  }  
  fclose(p);
  char *temp[numLinhas]; 

之后它进入一个循环,其中将文件中包含的语句的含义存储在string [i] 中。 for的开头和三个例子如下所示:

    for (i = 0; i<numLinhas; i++){
    sscanf( string[i], "%s %s %s %s" ,str1, str,str2, str3);
    if(str[0]=='0' && str[1] == '0' && str[2]!= 'd') {
    temp[i] = "NOP";
    count++;
    }
    if(str[0]=='0'&& str[1] == '6' && str[2]!= 'd') {
    sprintf(temp[i],"%s,%s" , "MVI B", str2);
    count = count+2;
    }

    if(str[0]=='0'&& str[1] == '7' && str[2]!= 'd') {
    temp[i] = "RLC";
    count++;
    }

错误是偶然的 - 它并不总是发生。它通常发生在调用 sprintf 时。 是啊!以下是我正在加载的 txt 文件作为示例:

0000 21a 11r 00r
0003 7Ea
0004 21a 12r 00r
0007 46a
0008 80a
0009 21a 13r 00r
000C 77a
000D 3Ea 01a
000F 3Da
0010 76a
0011 0Ad
0012 03d
0013 01d

刚看到一些新东西。这是我得到的编译窗口:

marcos@john:~/Desktop$ ./paraler
0000 21a 11r 00rValor de l: 16

Valor de l: 1
0003 7Ea
Valor de l: 9
0004 21a 12r 00rValor de l: 16

Valor de l: 1
0007 46a
Valor de l: 9
0008 80a
Valor de l: 9
0009 21a 13r 00rValor de l: 16

Valor de l: 1
000C 77a
Valor de l: 9
000D 3Ea 01a
Valor de l: 13
000F 3Da
Valor de l: 9
0010 76a
Valor de l: 9
0011 0Ad
Valor de l: 9
0012 03d
Valor de l: 9
0013 01d
Valor de l: 9
string:0000 21a 11r 00r
string:

string:0003 7Ea

string:0004 21a 12r 00r
string:

string:0007 46a

string:0008 80a

string:0009 21a 13r 00r
string:

string:000C 77a

string:000D 3Ea 01a

string:000F 3Da

string:0010 76a

string:0011 0Ad

string:0012 03d

string:0013 01d

Segmentation fault

奇怪的是,我得到了一些字符串数组的空格......它与错误有什么关系吗?

【问题讨论】:

  • 你试过在调试器中运行你的代码吗?
  • 第 1 步是将不安全的 sprintf 替换为安全的 snprintf。
  • 请对您的代码格式进行一些处理。第二位的缩进看起来搞砸了。
  • 注意 strncpy。在 strncpy(string[i], line, 17); 中,如果一行是 17 个字符或更多字符,则不写入 nul 终止符,并且 string[i] 并不真正包含字符串。

标签: c string segmentation-fault


【解决方案1】:

您是否在调用sprintf 之前为每个temp[i] 分配内存?如果没有,那就是你的问题。

if (!strncmp(str, "06", 2) && str[2] != 'd')
{
  temp[i] = malloc(5 + strlen(str2) + 2);  // Thanks, philippe
  if (temp[i])
    sprintf(temp[i], "%s,%s", "MVI B", str2);
}

尽管现在您必须跟踪temp 的哪些元素被分配了malloc,以便您以后可以释放它们。

编辑

在程序结束时,您可以循环遍历 temp 数组并根据上面字符串的前导部分检查每个元素的内容,如果它们匹配,则使用 free 取消分配该元素:

for (i = 0; i < numLinhas; i++)
{
  if (strcnmp(temp[i], "MVI B", strlen("MVI B")) == 0)
    free(temp[i]);
}

您不需要对分配了“NOP”或“RLC”的数组元素执行此操作;在这些情况下,您只需将字符串文字的 address 复制到数组元素。没有为这些元素分配新内存,因此您不必担心释放它们。

【讨论】:

  • 我确实在所有 sprint 中都更改了它,但我仍然遇到 Segfault.. 而且我什至将 sprint 更改为 snprint 以更安全...
  • 我猜应该是 temp[i] = malloc(5 + strlen(str2) + 2); 来解释 sprintf 格式的逗号。
  • 哇!非常感谢!这真的解决了我遇到的问题!
  • 我对 C 有点陌生,所以请原谅这个愚蠢的问题,但是如何在程序结束时释放分配的内存?
  • @Marcos, free(ptr),但您需要跟踪这些指针。
【解决方案2】:

我立即看到了一些问题:

编辑第一点可能不适用于您的环境,但您应该牢记这一点

  • 您正试图从一个整数创建char *temp[numLinHas],其值将在运行时确定。这在 C99 中是允许的,或者可以通过编译器扩展提供,但在较旧的 C 标准中,数组大小必须在编译时知道。你的代码可能真的是这样做的:

    int numLinHas = 0;
    char *temp[numLinHas];
    
  • 另一个问题是,当您执行sprintf 时,您试图复制到temp 中的某些内容,而没有为指针分配内存来存储字符串。

【讨论】:

  • 从 C99 开始,允许创建一个直到运行时才知道大小的数组,因此这是合法的 C99 代码。关于temp 的每个元素未被分配的第二点是有效的。
  • @John - 谢谢你提醒我,我记得 C99 有这样的设施。它可能适用于 OP,也可能不适用于 OP,因为他没有提到他的编译器。
  • 对不起!忘了说我是用gcc编译的
  • @Marcos - 那么您可能不会遇到问题 1,因为 gcc 确实允许在运行时将可变长度数组作为编译器扩展。
【解决方案3】:
if(str[0]=='0'&& str[1] == '6' && str[2]!= 'd') {
    /* allocate memory to store instruction - to be freed later */  
    temp[i] = malloc(5 + strlen(str2) + 2); /* +2 for the comma */
    sprintf(temp[i],"%s,%s" , "MVI B", str2);
    count = count+2;
    }

遇到以06开头且不以d结尾的助记符时会出现问题; sprintf() 写入非分配区域,因为 temp[i] 未初始化。您应该分配一些空间来存储 sprintf 的结果。

【讨论】:

  • 我应该在哪里做这个?在 sprintf 之前或当我声明数组 char temp[]?
  • 不,snprintf() 不会在这里改变任何东西。 temp 是一个指针数组。这对 NOP 和 RLC 来说很好,因为您将指向“RLC”或“NOP”字符串的指针分配给 temp[i]。使用MVI,需要分配足够的空间来存储“MVI B,n”字符串。
  • @Marcos - 不,snprintf 只是sprintf 的一种更安全的形式,它允许您限制结果字符串中的字符数。如果您使用char *temp[numLinHas] 之类的指针,您仍然需要使用malloc。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-19
  • 2019-01-28
  • 2020-01-23
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多