Avatar billede ahv Nybegynder
31. august 2007 - 19:11 Der er 41 kommentarer og
1 løsning

Fejl overskrivning af array

Hej C eksperter,

Jeg er ved at få grå hår af det her problem, jeg er ikke vant til at kode i C, men kan dog formåe at bikse lidt sammen ud fra min viden fra andre sprog.

Jeg har bikset følgende sammen;
http://ahv.dk/test_310807.cpp

Problemet er at mit array exonLoc bliver overskrevet med andet data. Jeg har forsøgt at udskrive noget data rundt omkring i mine if-sætninger og de kører som de skal.

Her er et skærmbillede af hvordan data tager sig ud mens den gennemgår filen og hvordan det tager sig ud bagefter når jeg gennemgår array'et i en for-løkke;
http://ahv.dk/ss.jpg

Hvordan kan det ske og hvordan undgår jeg det?
Avatar billede arne_v Ekspert
31. august 2007 - 19:31 #1
Jeg ved ihvertfald en ting som er gal.

char *find(char *s, char *start, char *end)
{
    char *p,*p2 = 0,tmp[1000];
...
      return tmp;
...
}

du maa ikke returnere adressen paa en lokal variabel !
Avatar billede arne_v Ekspert
31. august 2007 - 19:32 #2
Lav tmp global eller send den med som argument.
Avatar billede arne_v Ekspert
31. august 2007 - 19:33 #3
En anden ting.

char *exonLoc[1000][1];
...
exonLoc[i][1] = exonLocE;

Du kan kun bruge index 0 paa noget som har dimension 1.
Avatar billede arne_v Ekspert
31. august 2007 - 19:33 #4
Den skal no vaere dimension 2.
Avatar billede ahv Nybegynder
31. august 2007 - 19:33 #5
Hej arne,

Ja min compiler klager godt nok over det, men kører det alligevel. Kan du forklare hvad det betyder? Jeg har blot ladet det være fordi jeg ikke viste hvordan jeg løste det og hvad det betyder.
Avatar billede ahv Nybegynder
31. august 2007 - 19:37 #6
Jeg har gjort tmp global og rettet mit array til char *exonLoc[1000][2]; og exonLoc[i][1] = exonLocS; samt exonLoc[i][2] = exonLocE;

Det fjernede min warning men løste ikke problemet.
Avatar billede arne_v Ekspert
31. august 2007 - 19:43 #7
Med dimension 2 skal du bruge index 0 og 1.
Avatar billede arne_v Ekspert
31. august 2007 - 19:44 #8
Den memory som en lokal variabel ligger i frigives ved return og den bliver derfor
genbrugt.
Avatar billede ahv Nybegynder
31. august 2007 - 19:49 #9
Ok. Jeg har også rettet mit array til at bruge index 0 og 1.

Følgende fil kan evt bruges til test;
http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=nuccore&qty=1&c_start=1&list_uids=5016088&uids=&dopt=gbc&dispmax=1&sendto=t&fmt_mask=0&extrafeatpresent=1&ef_STS=64&ef_Exon=512&ef_CDD=8&ef_MGC=16&ef_HPRD=32&ef_tRNA=128&ef_microRNA=256

Hvis man bruger den fil, var formålet at arrayet skulle indeholde;
exonLoc[0][0] = 1, exonLoc[0][1] = 67
exonLoc[1][0] = 68, exonLoc[1][1] = 196
exonLoc[2][0] = 197, exonLoc[2][1] = 436
exonLoc[3][0] = 437, exonLoc[3][1] = 875
exonLoc[4][0] = 876, exonLoc[4][1] = 1057
exonLoc[5][0] = 1058, exonLoc[5][1] = 1793
Avatar billede ahv Nybegynder
31. august 2007 - 21:09 #10
Jeg har prøvet at finde ud af hvor fejlen er. Det ser ud til at det er i find funktionen. Når den køres med korrekt xml tag, men indholdet ikke er ok går det galt.

Nogen ide til, hvordan jeg løser det?
Avatar billede arne_v Ekspert
31. august 2007 - 21:41 #11
Kan du give et eksempel på de data den ikke virker med ?
Avatar billede ahv Nybegynder
31. august 2007 - 21:47 #12
Hvis jeg smider indholdet af den her side;
http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db=nuccore&qty=1&c_start=1&list_uids=5016088&uids=&dopt=gbc&dispmax=1&sendto=t&fmt_mask=0&extrafeatpresent=1&ef_STS=64&ef_Exon=512&ef_CDD=8&ef_MGC=16&ef_HPRD=32&ef_tRNA=128&ef_microRNA=256

i en txt fil og kører det, så virker det ikke.

Når jeg kører for-løkken, hvor jeg vil have den til at udskrive positionerne som anført i min tidligere kommentar skriver den som det kan ses på billedet fra første post bare polyA_site, hvilket er indholdet af et INSDFeature_key.

Jeg ønsker at hive start og slut positioner ud af det dokument når INSDFeature_key tag'et indeholder exon.
Avatar billede ahv Nybegynder
31. august 2007 - 23:29 #13
Jeg har forsøgt mig frem og problemet ser ud til at opstå når tmp returneres. Nogen ide til, hvorfor og hvordan det løses?
Avatar billede arne_v Ekspert
01. september 2007 - 00:16 #14
Hvordan ser koden ud nu ?
Avatar billede ahv Nybegynder
01. september 2007 - 00:33 #15
Den ser således ud;
http://ahv.dk/test_310807.cpp
Avatar billede arne_v Ekspert
01. september 2007 - 00:39 #16
Der er stadig mange ting som falder i øjnene:

* find bør nok returnere 0/1 (false/true) fremfor strenge

* er det virkeligt status og ikke tmp som du vil gemme i exonLoc ??

* find vil crashe hvis end tag ikke findes

Det sidste skal løses med enten at returnere hvis p2 er NULL eller ved at få læst hele filen
ind inden du parser (jeg antager at alle tags i filen er afsluttet).
Avatar billede ahv Nybegynder
01. september 2007 - 00:50 #17
Jeg har forsøgt at rette det til efter din anvisning;
http://ahv.dk/test_310807.cpp

Problemet er der stadig.
Avatar billede ahv Nybegynder
01. september 2007 - 01:38 #18
Jeg har leget lidt med koden,;
http://ahv.dk/test_310807.cpp

Problemet er der endnu. Hvordan kan det være at find laver bøvl med array'et? Hvis jeg bare giver mit array en statisk værdi find ikke bliver kørt er alt som det burde være.
Er det mon strncpy som laver noget bøvl?
Avatar billede arne_v Ekspert
01. september 2007 - 02:47 #19
Kan du ikke fortælle hvad du vil have ud af den XML fil, så kan jeg prøve at skrive noget kode til det ?
Avatar billede ahv Nybegynder
01. september 2007 - 09:32 #20
Hej arne,

Jeg vil gerne have positionsintervallet ud hver gang der har været; <INSDFeature_key>exon</INSDFeature_key>.

Når den linie har været der kommmer positionsintervallet et par linier efter f.eks;
<INSDInterval_from>437</INSDInterval_from>
<INSDInterval_to>875</INSDInterval_to>

Der kan være et vilkårligt antal exon's (i den givne xml fil er der 6) og dermed et vilkårligt antal intervaller.

Intervallerne skal bruges til at klippe i <INSDSeq_sequence></INSDSeq_sequence> som indeholder en lang sekvens. De opdelte sekvensstykker vil jeg gerne have i et array.
Avatar billede ahv Nybegynder
01. september 2007 - 15:44 #21
Hej arne,

Jeg har løst problemet, hvis jeg konverterer fra char til int på tmp virker det, hvorfor ved jeg ikke og hvorfor jeg prøvede ved jeg egentlig heller ikke.
Jeg vil meget gerne se, hvis du har skrevet noget som virker.

Jeg har rettet til;
exonLoc[i][0] = atoi(tmp); og exonLoc[i][1] = atoi(tmp);
Avatar billede arne_v Ekspert
02. september 2007 - 05:10 #22
Her er min rå C kode:

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

#define MAXFILESIZ 1000000
#define MAXELMSIZ 100000
#define MAXPAIR 100

static char tmp[MAXELMSIZ];

char *find(char *s, char *start, char *end)
{
    char *p, *p2;
    p = strstr(s, start);
    p2 = strstr(p, end);
    strncpy(tmp, p + strlen(start), p2 - p - strlen(start));
    tmp[p2 - p - strlen(start)] = '\0';
    return tmp;
}

void multifind(char *s, char *start, char *end, void (*f)(char *))
{
    char *p, *p2, tmp[MAXELMSIZ];
    p = s;
    while((p = strstr(p, start)) != NULL)
    {
        p2 = strstr(p, end);
        strncpy(tmp, p + strlen(start), p2 - p - strlen(start));
        tmp[p2 - p - strlen(start)] = '\0';
        f(tmp);
        p = p2;
    }
}

static int npair;
static int pairfrom[MAXPAIR];
static int pairto[MAXPAIR];

void process_sequencepart(char *s)
{
    printf("exon sequnce part = %s\n", s);
}

void process_feature(char *s)
{
    if(strcmp(find(s, "<INSDFeature_key>", "</INSDFeature_key>"), "exon") == 0)
    {
        pairfrom[npair] = atoi(find(s, "<INSDInterval_from>", "</INSDInterval_from>"));
        pairto[npair] = atoi(find(s, "<INSDInterval_to>", "</INSDInterval_to>"));
        npair++;
    }
}

void process(char *s)
{
    int i;
    char *sequence, part[MAXELMSIZ];
    npair = 0;
    multifind(s, "<INSDFeature>", "</INSDFeature>", process_feature);
    sequence = find(s, "<INSDSeq_sequence>", "</INSDSeq_sequence>");
    for(i = 0; i < npair; i++)
    {
        strncpy(part, sequence + pairfrom[i], pairto[i] - pairfrom[i] + 1);
        part[pairto[i] - pairfrom[i] + 1] = '\0';
        process_sequencepart(part);
    }
}

int main()
{
    FILE *fp;
    char buf[MAXFILESIZ],*p;
    fp = fopen("INSD.xml", "r");
    p = buf;
    while(fgets(p, MAXFILESIZ - (p - buf), fp))
    {
        p += strlen(p);
    }
    fclose(fp);
    process(buf);
    return 0;
}
Avatar billede arne_v Ekspert
02. september 2007 - 06:18 #23
Og her er så den samme kode ved brug af LIBXML2 og XPATH:

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

#include "libxml/parser.h"
#include "libxml/tree.h"
#include "libxml/xpath.h"

#define MAXELMSIZ 100000
#define MAXPAIR 100

void process_sequencepart(char *s)
{
    printf("exon sequnce part = %s\n", s);
}

int main()
{
    int i, npair, pairfrom[MAXPAIR], pairto[MAXPAIR];
    char *sequence, part[MAXELMSIZ];
    xmlDocPtr doc;
    xmlXPathContextPtr xpathCtx;
    xmlXPathObjectPtr xpathObj;
    xmlNodePtr elm;
    xmlInitParser();
    doc = xmlParseFile("INSD.xml");
    xpathCtx = xmlXPathNewContext(doc);
    xpathObj = xmlXPathEvalExpression("//INSDSet/INSDSeq/INSDSeq_feature-table/INSDFeature[INSDFeature_key='exon']/INSDFeature_intervals/INSDInterval/INSDInterval_from", xpathCtx);
    npair = xpathObj->nodesetval->nodeNr;
    for(i = 0; i < xpathObj->nodesetval->nodeNr; i++)
    {
        elm = xpathObj->nodesetval->nodeTab[i];
        pairfrom[i] = atoi(elm->children->content);
    }
    xpathObj = xmlXPathEvalExpression("//INSDSet/INSDSeq/INSDSeq_feature-table/INSDFeature[INSDFeature_key='exon']/INSDFeature_intervals/INSDInterval/INSDInterval_to", xpathCtx);
    for(i = 0; i < xpathObj->nodesetval->nodeNr; i++)
    {
        elm = xpathObj->nodesetval->nodeTab[i];
        pairto[i] = atoi(elm->children->content);
    }
    xpathObj = xmlXPathEvalExpression("//INSDSet/INSDSeq/INSDSeq_sequence", xpathCtx);
    sequence = xpathObj->nodesetval->nodeTab[0]->children->content;
    for(i = 0; i < npair; i++)
    {
        strncpy(part, sequence + pairfrom[i], pairto[i] - pairfrom[i] + 1);
        part[pairto[i] - pairfrom[i] + 1] = '\0';
        process_sequencepart(part);
    }
    xmlXPathFreeContext(xpathCtx);
    xmlFreeDoc(doc);
    xmlCleanupParser();
    return 0;
}
Avatar billede ahv Nybegynder
02. september 2007 - 16:00 #24
Hej arne,

Din kode virker fint, tak.

Der er dog stadig et problem, som jeg håber på du har en forklaring og løsning til.
Hvorfor overskriver den i array'et, hvis jeg ikke laver en konvertering med atoi? Lad os f.eks. antage at jeg havde noget tekst istedet for. Hvordan skal det konverteres for at den ikke overskriver?
Avatar billede arne_v Ekspert
02. september 2007 - 16:11 #25
Jeg ved det ikke.

Den nyeste kode på download linket bruger ikke atoi - og den crasher ikke hos mig
men skriver dog:

0 Start 1793 End: 1793
1 Start 1793 End: 1793
2 Start 1793 End: 1793
3 Start 1793 End: 1793
4 Start 1793 End: 1793
5 Start 1793 End: 1793

ud, hvilket jo er logisk forkert.

Hvis jeg skulle gætte på hvad der går galt, så er det fordi du bare gemmer en pointer til data
som genbruges i.s.f. at strcpy/strncpy data til en ny buffer.
Avatar billede ahv Nybegynder
02. september 2007 - 16:19 #26
Nu hvor jeg kan konvertere denne pointer med atoi til int, kan jeg så også konvertere en pointer til en streng?
Avatar billede arne_v Ekspert
02. september 2007 - 16:29 #27
Det er ca. detjeg gør med:

char part[MAXELMSIZ];
strncpy(part, sequence + pairfrom[i], pairto[i] - pairfrom[i] + 1);
part[pairto[i] - pairfrom[i] + 1] = '\0';

fremfor:

char *part;
part = sequence + pairfrom[i];

(den sidste har dog også et problem med termineringen)
Avatar billede arne_v Ekspert
02. september 2007 - 17:21 #28
Nu kan jeg se at du inkluderer iostream (dog uden at bruge den).

Er C++ ok ?

Ved at ændre fra C til C++ kunne man pynte en hel del på koden !
Avatar billede ahv Nybegynder
02. september 2007 - 18:10 #29
Såfremt at jeg kan få en tekststreng ind i mit array, ville jeg da gerne se en sådan løsning. Jeg har dog aldrig rodet med C++, men jeg kan sikkert sjusse mig frem til noget, når jeg ser noget andet kode.

Jeg har smidt min kode op med hvad jeg har nu, hvordan vil den se ud i c++?
http://ahv.dk/test_020907.cpp
Avatar billede ahv Nybegynder
02. september 2007 - 18:15 #30
Problemet med min egen kode er nu, at den sekvens jeg prøver at smide ind i mit array bliver overskrevet, som det var problemet tidligere med intervallerne.

Jeg har ikke lavet funktioner i min egen kode, da jeg egentlig bare gerne ville have det til at virke først. Så kan jeg altid pynte på koden senere.
Avatar billede arne_v Ekspert
02. september 2007 - 19:18 #31
Den er gal med index igen.

for (k=1; k <= 2; k++)

duer ikke som index for arrays med dimension [2]
Avatar billede ahv Nybegynder
02. september 2007 - 19:19 #32
Ups, jeg retter asap :)
Avatar billede ahv Nybegynder
02. september 2007 - 19:19 #33
Jeg arbejder på en workaround såfremt det heller ikke duer i c++.
Avatar billede arne_v Ekspert
02. september 2007 - 19:23 #34
Der er ikke så stor forskel på C og C++.

Men det bør kunne gøres mere sikkert i C++.
Avatar billede arne_v Ekspert
02. september 2007 - 19:24 #35
Og jeg tror ikke på "få det til at virke og så pynt koden" logikken - det er en hjælp
til at få det til at virke at opdele ens kode i små funktioner.
Avatar billede arne_v Ekspert
02. september 2007 - 19:33 #36
Jeg prøver lige at lave noget C++ kode.
Avatar billede arne_v Ekspert
02. september 2007 - 19:58 #37
Her er den samme rå kode i C++:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <vector>

using namespace std;

string find(string s, string start, string end)
{
    return s.substr(s.find(start) + start.length(), s.find(end) - s.find(start) - start.length());
}

void multifind(string s, string start, string end, void (*f)(string))
{
    int ix = 0;
    while((ix = s.find(start, ix)) != string::npos)
    {
        int ix2 = s.find(end, ix);
        f(s.substr(ix + start.length(), ix2 - ix - start.length()));
        ix = ix2;
    }
}

static vector<int> pairfrom;
static vector<int> pairto;

void process_sequencepart(string s)
{
    cout << "exon sequnce part = " << s << endl;
}

void process_feature(string s)
{
    if(find(s, "<INSDFeature_key>", "</INSDFeature_key>") == "exon")
    {
        pairfrom.push_back(atoi(find(s, "<INSDInterval_from>", "</INSDInterval_from>").c_str()));
        pairto.push_back(atoi(find(s, "<INSDInterval_to>", "</INSDInterval_to>").c_str()));
    }
}

void process(string s)
{
    multifind(s, "<INSDFeature>", "</INSDFeature>", process_feature);
    string sequence = find(s, "<INSDSeq_sequence>", "</INSDSeq_sequence>");
    for(int i = 0; i < pairfrom.size(); i++)
    {
        string part = sequence.substr(pairfrom[i], pairto[i] - pairfrom[i] + 1);
        process_sequencepart(part);
    }
}

int main()
{
    ifstream f("INSD.xml");
    string buf = "";
    string line;
    while(getline(f,line))
    {
        buf += line;
    }
    f.close();
    process(buf);
    return 0;
}
Avatar billede arne_v Ekspert
03. september 2007 - 01:07 #38
Og endnu en gang - denne gang i PHP !!

<?php
function find($s, $start, $end) {
    return substr($s, strpos($s, $start) + strlen($start), strpos($s, $end) - strpos($s, $start) - strlen($start));
}

function multifind($s, $start, $end, $f) {
    $ix = 0;
    while(($ix = strpos($s, $start, $ix)) !== False) {
        $ix2 = strpos($s, $end, $ix);
        $f(substr($s, $ix + strlen($start), $ix2 - $ix - strlen($start)));
        $ix = $ix2;
    }
}

$pairfrom = array();
$pairto = array();

function process_sequencepart($s) {
    echo "exon sequnce part = " . $s . "\n";
}

function process_feature($s) {
    global $pairfrom;
    global $pairto;
    if(find($s, "<INSDFeature_key>", "</INSDFeature_key>") == "exon")
    {
        $pairfrom[] = intval(find($s, "<INSDInterval_from>", "</INSDInterval_from>"));
        $pairto[] = intval(find($s, "<INSDInterval_to>", "</INSDInterval_to>"));
    }
}

function process($s) {
    global $pairfrom;
    global $pairto;
    multifind($s, "<INSDFeature>", "</INSDFeature>", process_feature);
    $sequence = find($s, "<INSDSeq_sequence>", "</INSDSeq_sequence>");
    for($i = 0; $i < sizeof($pairfrom); $i++) {
        $part = substr($sequence, $pairfrom[$i], $pairto[$i] - $pairfrom[$i] + 1);
        process_sequencepart($part);
    }
}

$buf = file_get_contents("INSD.xml");
process($buf);
?>
Avatar billede ahv Nybegynder
03. september 2007 - 19:31 #39
Arne, så mangler jeg bare asp og java ;)

Smid et svar, c++ ser ud til at kunne smide tekststrenge i et array uden at overskrive, så skal jeg nok kunne sjusse mig frem til resten med google.
Avatar billede ahv Nybegynder
03. september 2007 - 19:33 #40
Måske jeg skulle til at se på lidt C++, det ser ud til at minde en hel del om PHP.
Avatar billede arne_v Ekspert
03. september 2007 - 19:47 #41
svar
Avatar billede arne_v Ekspert
03. september 2007 - 19:48 #42
Man kan lave det samme fnadderi i C++ som i C hvis man vil, men hvis man bruger
nogle mere high level konstruktioner som STL (string og vector i eksemplet), så undgår
man en del problemer.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester