2015-09-28 2 views
-1

Я пытаюсь передать указатель на массив указателей на символ в функцию, где я хочу ее инициализировать.Ошибка инициализации массива 2d (segfault)

Однако моя реализация вызывает ошибку сегментации, и я не могу понять, почему. Может ли кто-нибудь помочь?

Вот мой код:

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

void ret_2darr(char *(*str)[5]) 
{ 
    int i,j; 
    for(i=0;i<3;i++) 
    { 
     for(j=0;j<=5;j++) 
     { 
      str[i][j]=(char *)malloc(sizeof("sach")); 
      strcpy(str[i][j],"sach"); 
     } 
    } 
} 

main() 
{ 
    char *(*a)[5]=NULL; 
    ret_2darr(a); 
    int i,j; 
    for(i=0;i<3;i++) 
    { 
     for(j=0;j<=5;j++) 
     { 
      printf("%s",a[i][j]); 
     } 
    } 
} 
+6

Что говорит отладчик? – amdixon

ответ

-1

В строке no.7 он должен быть символ * (* а) [5]; Нет необходимости определять varible a с NULL.

+0

Если вы скомпилируете опцию qwith gcc -Wall, она даст вам предупреждение: 'a' используется неинициализированным в этой функции [-Wuninitialized] – LPs

+0

А как насчет всех остальных ошибок: 'sizeof (« sach »)' недостаточно для того, чтобы strore эта строка и т. д. – LPs

+0

@LPs: Я выполнил код выше с помощью gcc -Wall, не выдавая никаких ошибок для функции sizeof. Это дает правильный результат. Исправьте меня, если я ошибаюсь ... – Koushik

1

консультации с отладчиком, он говорит:

$ gcc -g test.c -o test 
$ gdb ./test 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1 
Copyright (C) 2014 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-linux-gnu". 
Type "show configuration" for configuration details. 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>. 
Find the GDB manual and other documentation resources online at: 
<http://www.gnu.org/software/gdb/documentation/>. 
For help, type "help". 
Type "apropos word" to search for commands related to "word"... 
Reading symbols from ./test...done. 
(gdb) run 
Starting program: /home/xand/code/stackoverflow/c/test 

Program received signal SIGSEGV, Segmentation fault. 
0x000000000040064a in ret_2darr (str=0x0) at test.c:26 
26  str[i][j]=(char *)malloc(sizeof("sach")); 
(gdb) print str 
$1 = (char *(*)[5]) 0x0 

, что означает в ret_2darr при попытке доступа ул он пустой. нуль Разыменование вызывает Segfault ..

оглядываясь на то, как ул определяется и используется:

char *(*a)[5]=NULL; 

мы видим, что это символ ** [5] (это начало проблемы).

Поскольку нам нужно всего лишь сохранить пять строк, это должно быть как символ * [5].

исправляя это и поток по вопросам дает

другие исправления

  • corrected main prototype and added flow on return 0..
  • redefined a properly
  • corrected bounds error <=5 goes to < 5 (two times)
  • removed malloc cast as redundant
  • added \n for proper printing..
  • added free(a[j]) to cleanup memory
  • handle allocation errors from malloc

скорректированный код

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

int ret_2darr(char *a[5]); 

int main(void) 
{ 
    char *a[5]; 
    if(ret_2darr(a)) 
    { 
    // handle/log allocation errors here.. 
    return 0; 
    } 
    int i,j; 
    for(j=0;j<5;j++) 
    { 
    printf("%s\n",a[j]); 
    free(a[j]); 
    } 
    return 0; 
} 

int ret_2darr(char *str[5]) 
{ 
    int j; 
    memset(str, 5*sizeof(char *), 0); 
    for(j=0;j<5;j++) 
    { 
    str[j]=malloc(sizeof("sach")); 
    if(!str[j])goto err0; 
    strcpy(str[j],"sach"); 
    } 
    return 0; 

err0: 
    for(;j>=0;j--) 
    { 
    if(str[j])free(str[j]); 
    } 
    return 1; 
} 

выход

$ gcc -g test.c.fixed.c -o test 
$ valgrind ./test 
==18525== Memcheck, a memory error detector 
==18525== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. 
==18525== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info 
==18525== Command: ./test 
==18525== 
sach 
sach 
sach 
sach 
sach 
==18525== 
==18525== HEAP SUMMARY: 
==18525==  in use at exit: 0 bytes in 0 blocks 
==18525== total heap usage: 5 allocs, 5 frees, 25 bytes allocated 
==18525== 
==18525== All heap blocks were freed -- no leaks are possible 
==18525== 
==18525== For counts of detected and suppressed errors, rerun with: -v 
==18525== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

ссылка

+0

"мы видим, что это char *** (это начало проблемы). Поскольку нам нужно хранить массив строк, это должно быть как char **". Да, что? Это нонсенс. 2D-массив не является указателем на указатель и не совместим. Пожалуйста, исправьте, так как я не хочу голосовать в противном случае хорошим ответом. – Lundin

2

Рассмотрим этот тривиальный код:

int a = 0; 
func(a); 
... 

void func (int x) 
{ 
    x = 5; 
} 

Этот код не изменяет переменную a, так как функция только модифицировала копию переменной, а не фактическое ее содержимое.

Указатели или указатели массива не отличаются друг от друга, если вы назначаете указатель, переданный как параметр, указывать в другом месте, это присвоение действительно только в этой функции. Поэтому вам нужно будет передать адрес указателю. Это основная ошибка: функция только создаст утечку памяти, так как у вас есть временный указатель, указывающий на выделенную память, которая забывается, как только функция возвращается.

Итак, вам нужно будет передать указатель массива по адресу ..., который является реальной сложной частью. Ваши параметры передают указатель на указатель массива или возвращают указатель массива. Либо будет производить некоторый серьезно злой код C:

void ret_2darr(char *(**str)[5]) // pass array pointer by reference 

или

char* (*(*ret_2darr)(void))[5]; // return array pointer from function 

Не писать подобный код, хотя! Это непроницаемый беспорядок. typedef - единственное разумное решение здесь. Например:

typedef char* arr_t[5]; // the array type 
arr_t* ptr; // a pointer to that array type 

Других ошибки:

  • Вы на самом деле не выделить массив указателей в любом месте, вы только начинаете выделять элементы массива без выделения самого массива существующего.

  • Вам, похоже, нужен 2D-массив, но вы используете тип массива 1D. Указатель массива должен был быть char *(*a)[3][5].

  • Вы неправильно обращаетесь к указателю на массив. str[i][j] означает «в номере массива [i], дайте мне sub-array [j]», где вы скорее захотите «в моем 2D-массиве char *, дайте мне элемент [i] [j]». Опять же, решите, сколько у вас размеров.

  • Вы петлевые более 6 индексов не 5 и т.д.


Я настоятельно рекомендую просто забыть про указатели массива полностью, по крайней мере, насколько эта функция озабочен. Оставьте выделение фактического 2D-массива вызывающему. Вместо этого используйте char* arr[3][5].

Смежные вопросы