Я пишу программу Objective-C для работы с траекториями биомолекул с XCODE 4.3.1 и ARC. Мне нужно читать файлы PDB, т.е. анализировать большое количество данных в текстовом формате. Я очень разочарован неэффективностью NSString и пытался написать C-эквивалент компонентовSeparatedByString:. Алгоритм отлично работает с NSString и NSMutableArrays, но мне трудно использовать char* и char**.
К сожалению, я получаю сообщение об ошибке EXC_BAD_ACCESS. Странно то, что я получаю ошибку для i=68103 и j=68049 (эти числа звонят вам в колокол?), что означает, что он работал некоторое время перед сбоем. Ошибка "статическая" (всегда блокируется на одних и тех же (i,j) числах). Кажется, что массив работает нормально (NSLog по его значениям перед сбоем).
Как кажется, я не очень разбираюсь в C-коде и тонкостях указателей, но я определенно был бы рад услышать ваши предложения, чтобы заставить его работать! Спасибо !
Вот код:
+(char**) componentsSeparedByNewLineCEQUIV:(const char*)aChar:(int*)numWord
{ // char* aChar : my file, is typically 3 millions characters
int j=-1; //Last non space character
int i; //Scanned character
int len=strlen(aChar);
char** stringArray=malloc((*numWord)*sizeof(char*));
for (i=0;i<len; i++)
{ if (aChar[i]==10)
{
if ( j!=-1)
{
char* buffer2=malloc(i-j+1);
strcpy(buffer2, strndup(aChar+j, i-j));
stringArray[i]=malloc(sizeof(char)*strlen(buffer2)+1); //EXC_BAD_ACCESS HERE
strcpy(stringArray[i], buffer2);
}
j=-1;
}
else if (j==-1)
{j=i;}
}
if (j!=-1)
{ char* buffer2=malloc(i-j+1);
strcpy(buffer2, strndup(aChar+j, i-j));
stringArray[i]=malloc(strlen(buffer2)+1);
strcpy(stringArray[i], buffer2);
}
return stringArray;
}
Ответ 1 · deanWombourne
Вы, наверное, не первый, кто столкнулся с этой проблемой :)
Почему бы просто не использовать strtok?
PS Какой анализ показал, что проблема именно в NSString?
Ответ 2 · Ramy Al Zuhouri
Я не знаю, почему ошибка находится в строке выше, где она должна быть. Однако вы копируете строку, которая не выделена.
stringArray[i] не выделяется, когда вы копируете на него буфер2, выделите его:
if ( j!=-1)
{
char* buffer2=malloc(i-j+1);
strcpy(buffer2, strndup(aChar+j, i-j));
stringArray[i]=malloc(sizeof(char)*strlen(buffer2)+1); //EXC_BAD_ACCESS HERE
stringArray[i]=(char*)malloc( (strlen(buffer2)+1)*sizeof(char)); // Allocate the string
strcpy(stringArray[i], buffer2);
}
Ответ 3 · Jonathan Cichon
Во-первых: если я не совсем ошибаюсь, но я думаю, что вы потребляете как минимум в 4 раза больше памяти, чем вам нужно:
Вы используете malloc для создания buffer2, а также используете strndup для получения нужных символов. strndup делает именно то, что вы хотите, но за один шаг. char* buffer2 = strndup(aChar+j, i-j) должно быть вашим первым шагом. Хуже того, в следующих двух строках вам необходимо сделать то же самое снова. Так что я думаю, что вы действительно хотите, это stringArray[i] = strndup(aChar+j, i-j). Чтобы посмотреть на проблемы с памятью: все функции используют errno для обозначения сбоя выделения памяти.
Во-вторых: ваши функции не возвращают количество компонентов, поэтому ваш stringArray может содержать какой-то мусор без ведома.
Третье: strlen дорого и вам это не нужно, просто используйте for(int i = 0; aChar[i] != '\0'; i++)
Ответ 4 · Bertrand Caron
Обновление для всех, кому это может быть интересно: это рабочая версия, использующая strtok, которая может быть полезна, хотя мне все еще интересен ответ на мой код.
Этот код был протестирован в 5 раз быстрее (125 мс против 581 мс), чем [string componentSeparatedByString:@"\n"] ...
+(char**)componentsSeparatedByNewLine:(const char*)aChar:(int*)numWord
{
int i;
int j=0;
int len = strlen(aChar);
*numWord=1;
for (i=0;i<len; i++)
{
if (aChar[i]==10) *numWord=*numWord+1; //change 10 for any other character (ASCII for space)
}
char** stringArray=malloc((*numWord)*sizeof(char*));
char* pch;
char* aChar2=malloc(len+1);
strcpy(aChar2,aChar);
pch = strtok(aChar2,"\n");
while (pch != NULL)
{
stringArray[j]=(char*)malloc( (strlen(pch)+1)*sizeof(char));
strcpy(stringArray[j], pch);
//NSLog(@"%s",stringArray[j]);
j=j+1;
pch = strtok (NULL, "\n");
}
return stringArray;
}