2012-10-06 19 views
29

मुझे कुछ प्रोग्राम में कोई समस्या है, मैंने सेगमेंटेशन दोषों की खोज की है, क्योंकि मैं उन्हें बहुत अच्छी तरह समझ नहीं पा रहा हूं, केवल एक चीज मुझे पता है कि संभवतः मैं कुछ स्मृति तक पहुंचने की कोशिश कर रहा हूं। नहीं करना चाहिए। समस्या यह है कि मैं अपना कोड देखता हूं और समझ नहीं पा रहा हूं कि मैं क्या गलत कर रहा हूं।सेगमेंटेशन गलती: 11

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

#define lambda 2.0 
#define g  1.0 
#define Lx  100 
#define F0  1.0 
#define Tf  10 
#define h  0.1 
#define e  0.00001 

FILE *file; 

double F[1000][1000000]; 

void Inicio(double D[1000][1000000]) { 
int i; 
for (i=399; i<600; i++) { 
    D[i][0]=F0; 
} 
} 

void Iteration (double A[1000][1000000]) { 
long int i,k; 
for (i=1; i<1000000; i++) { 
    A[0][i]= A[0][i-1] + e/(h*h*h*h)*g*g*(A[2][i-1] - 4.0*A[1][i-1] + 6.0*A[0][i-1]-4.0*A[998][i-1] + A[997][i-1]) + 2.0*g*e/(h*h)*(A[1][i-1] - 2*A[0][i-1] + A[998][i-1]) + e*A[0][i-1]*(lambda-A[0][i-1]*A[0][i-1]); 
    A[1][i]= A[1][i-1] + e/(h*h*h*h)*g*g*(A[3][i-1] - 4.0*A[2][i-1] + 6.0*A[1][i-1]-4.0*A[0][i-1] + A[998][i-1]) + 2.0*g*e/(h*h)*(A[2][i-1] - 2*A[1][i-1] + A[0][i-1]) + e*A[1][i-1]*(lambda-A[1][i-1]*A[1][i-1]); 
    for (k=2; k<997; k++) { 
     A[k][i]= A[k][i-1] + e/(h*h*h*h)*g*g*(A[k+2][i-1] - 4.0*A[k+1][i-1] + 6.0*A[k][i-1]-4.0*A[k-1][i-1] + A[k-2][i-1]) + 2.0*g*e/(h*h)*(A[k+1][i-1] - 2*A[k][i-1] + A[k-1][i-1]) + e*A[k][i-1]*(lambda-A[k][i-1]*A[k][i-1]); 
    } 
    A[997][i] = A[997][i-1] + e/(h*h*h*h)*g*g*(A[0][i-1] - 4*A[998][i-1] + 6*A[997][i-1] - 4*A[996][i-1] + A[995][i-1]) + 2.0*g*e/(h*h)*(A[998][i-1] - 2*A[997][i-1] + A[996][i-1]) + e*A[997][i-1]*(lambda-A[997][i-1]*A[997][i-1]); 
    A[998][i] = A[998][i-1] + e/(h*h*h*h)*g*g*(A[1][i-1] - 4*A[0][i-1] + 6*A[998][i-1] - 4*A[997][i-1] + A[996][i-1]) + 2.0*g*e/(h*h)*(A[0][i-1] - 2*A[998][i-1] + A[997][i-1]) + e*A[998][i-1]*(lambda-A[998][i-1]*A[998][i-1]); 
    A[999][i]=A[0][i]; 
} 
} 

main() { 
long int i,j; 
Inicio(F); 
Iteration(F); 
file = fopen("P1.txt","wt"); 
for (i=0; i<1000000; i++) { 
    for (j=0; j<1000; j++) { 
     fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]); 
    } 
} 
fclose(file); 
} 

आपके समय के लिए धन्यवाद।

+0

सेगफॉल्ट किस बिंदु पर होता है? –

+1

^लाइन नंबर प्राप्त करने के लिए वालग्रिंड का उपयोग करने का प्रयास करें जहां segfault होता है। एक बार जब आप इसे एक पंक्ति तक सीमित कर देते हैं तो आम तौर पर यह स्पष्ट रूप से स्पष्ट होता है - यदि नहीं, तो यह कौन सी रेखा पोस्ट करें और हम सहायता कर सकते हैं। –

+3

अपना कोड देखकर, सबसे पहले आपके कंपाइलर सेगमेंटेशन गलती होनी चाहिए ... – perilbrain

उत्तर

62

इस घोषणा:

double F[1000][1000000]; 

एक ठेठ 86 सिस्टम पर 8 * 1000 * 1000000 बाइट्स का स्थान लेगा। यह लगभग 7.45 जीबी है। संभावना है कि आपका कोड निष्पादित करने का प्रयास करते समय आपकी प्रणाली मेमोरी से बाहर हो रही है, जिसके परिणामस्वरूप सेगमेंटेशन गलती होती है।

+0

धन्यवाद, वह था। – Ariaramnes

1

आप किस सिस्टम पर चल रहे हैं? क्या आपके पास कुछ प्रकार के डीबगर (जीडीबी, विजुअल स्टूडियो डीबगर, इत्यादि) तक पहुंच है?

इससे हमें मूल्यवान जानकारी मिल जाएगी, जैसे कोड की रेखा जहां प्रोग्राम दुर्घटनाग्रस्त हो ... इसके अलावा, स्मृति की मात्रा निषिद्ध हो सकती है।

इसके अतिरिक्त, क्या मैं अनुशंसा कर सकता हूं कि आप संख्यात्मक परिभाषाओं द्वारा संख्यात्मक सीमाओं को प्रतिस्थापित करें?

जैसे:

#define DIM1_SZ 1000 
#define DIM2_SZ 1000000 

उपयोग उन जब भी आप सरणी आयाम सीमा देखना चाहेंगे। यह टाइपिंग त्रुटियों से बचने में मदद करेगा।

0

efence से जुड़े valgrind के साथ अपना प्रोग्राम चलाएं। यह आपको बताएगा कि पॉइंटर को संदर्भित किया जा रहा है और यदि आप उन सभी त्रुटियों को ठीक करते हैं, तो वे आपकी समस्या को ठीक करते हैं।

29

आपकी सरणी लगभग 8 जीबी मेमोरी (1,000 x 1,000,000 x sizeof (डबल) बाइट्स पर कब्जा कर रही है)। यह आपकी समस्या में एक कारक हो सकता है। यह एक स्टैक वैरिएबल की बजाय एक वैश्विक चर है, इसलिए आप ठीक हो सकते हैं, लेकिन आप यहां सीमाएं दबा रहे हैं।

लिखना कि फ़ाइल में अधिक डेटा कुछ समय ले रहा है।

आप यह जांच नहीं करते कि फ़ाइल सफलतापूर्वक खोला गया था, जो भी परेशानी का स्रोत हो सकता है (यदि यह विफल हो गया है, तो सेगमेंटेशन गलती बहुत संभव है)।

आपको वास्तव में 1,000 और 1,000,000 के लिए कुछ नामित स्थिरांक पेश करना चाहिए; वे क्या प्रतिनिधित्व करते हैं?

आपको गणना करने के लिए एक फ़ंक्शन भी लिखना चाहिए; आप C99 या बाद में (या C++) में inline फ़ंक्शन का उपयोग कर सकते हैं। कोड में दोहराव देखने के लिए परेशान है। निष्क्रिय जिज्ञासा से बाहर

int main(void) 

:

तुम भी C99 अंकन main() के लिए (तर्क सूची के लिए जब आप argc या argv उपयोग नहीं कर रहे और अच्छा होगा यदि void) का उपयोग करना चाहिए, स्पष्ट वापसी प्रकार के साथ , मैंने आपके कोड की एक प्रति ली, 1000 से ROWS की सभी घटनाओं को बदल दिया, 1000000 से COLS की सभी घटनाओं को बदल दिया, और फिर enum { ROWS = 1000, COLS = 10000 }; बनाया (जिससे 100 के कारक द्वारा समस्या का आकार कम हो गया)।मैंने कुछ मामूली परिवर्तन किए हैं, इसलिए यह संकलन विकल्पों के मेरे पसंदीदा सेट के तहत साफ रूप से संकलित होगा (कुछ भी गंभीर नहीं: static कार्यों के सामने, और मुख्य सरणी; filemain पर स्थानीय हो जाता है; fopen() इत्यादि की जांच करें)।

मैंने फिर एक दूसरी प्रतिलिपि बनाई और दोहराई गई गणना करने के लिए एक इनलाइन फ़ंक्शन बनाया, (और सबकुछ गणना करने के लिए दूसरा)। इसका मतलब है कि राक्षसी अभिव्यक्ति केवल एक बार लिखी जाती है - जो अत्यधिक वांछनीय है क्योंकि यह स्थिरता सुनिश्चित करती है।

#include <stdio.h> 

#define lambda 2.0 
#define g  1.0 
#define F0  1.0 
#define h  0.1 
#define e  0.00001 

enum { ROWS = 1000, COLS = 10000 }; 

static double F[ROWS][COLS]; 

static void Inicio(double D[ROWS][COLS]) 
{ 
    for (int i = 399; i < 600; i++) // Magic numbers!! 
     D[i][0] = F0; 
} 

enum { R = ROWS - 1 }; 

static inline int ko(int k, int n) 
{ 
    int rv = k + n; 
    if (rv >= R) 
     rv -= R; 
    else if (rv < 0) 
     rv += R; 
    return(rv); 
} 

static inline void calculate_value(int i, int k, double A[ROWS][COLS]) 
{ 
    int ks2 = ko(k, -2); 
    int ks1 = ko(k, -1); 
    int kp1 = ko(k, +1); 
    int kp2 = ko(k, +2); 

    A[k][i] = A[k][i-1] 
      + e/(h*h*h*h) * g*g * (A[kp2][i-1] - 4.0*A[kp1][i-1] + 6.0*A[k][i-1] - 4.0*A[ks1][i-1] + A[ks2][i-1]) 
      + 2.0*g*e/(h*h) * (A[kp1][i-1] - 2*A[k][i-1] + A[ks1][i-1]) 
      + e * A[k][i-1] * (lambda - A[k][i-1] * A[k][i-1]); 
} 

static void Iteration(double A[ROWS][COLS]) 
{ 
    for (int i = 1; i < COLS; i++) 
    { 
     for (int k = 0; k < R; k++) 
      calculate_value(i, k, A); 
     A[999][i] = A[0][i]; 
    } 
} 

int main(void) 
{ 
    FILE *file = fopen("P2.txt","wt"); 
    if (file == 0) 
     return(1); 
    Inicio(F); 
    Iteration(F); 
    for (int i = 0; i < COLS; i++) 
    { 
     for (int j = 0; j < ROWS; j++) 
     { 
      fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]); 
     } 
    } 
    fclose(file); 
    return(0); 
} 

इस कार्यक्रम P2.txt बजाय P1.txt लिए लिखता है। मैं दोनों कार्यक्रम चला गया और आउटपुट फाइलों की तुलना की; आउटपुट समान था। जब मैंने अधिकतर निष्क्रिय मशीन (मैकबुक प्रो, 2.3 गीगाहर्ट्ज इंटेल कोर i7, 16 जीआईबी 1333 मेगाहर्ट्ज रैम, मैक ओएस एक्स 10.7.5, जीसीसी 4.7.1) पर कार्यक्रम चलाए, तो मुझे उचित रूप से मिला लेकिन पूरी तरह से समयावधि नहीं:

Original Modified 
6.334s  6.367s 
6.241s  6.231s 
6.315s  10.778s 
6.378s  6.320s 
6.388s  6.293s 
6.285s  6.268s 
6.387s  10.954s 
6.377s  6.227s 
8.888s  6.347s 
6.304s  6.286s 
6.258s  10.302s 
6.975s  6.260s 
6.663s  6.847s 
6.359s  6.313s 
6.344s  6.335s 
7.762s  6.533s 
6.310s  9.418s 
8.972s  6.370s 
6.383s  6.357s 

हालांकि, लगभग सभी समय डिस्क I/O पर खर्च किया जाता है। मैं डेटा का सिर्फ आखिरी पंक्ति करने के लिए डिस्क आई/ओ कम है, तो बाहरी मैं/हे for पाश बने:

for (int i = COLS - 1; i < COLS; i++) 

समय बेहद कम हो गई थी और बहुत अधिक संगत:

Original Modified 
0.168s  0.165s 
0.145s  0.165s 
0.165s  0.166s 
0.164s  0.163s 
0.151s  0.151s 
0.148s  0.153s 
0.152s  0.171s 
0.165s  0.165s 
0.173s  0.176s 
0.171s  0.165s 
0.151s  0.169s 

कोड में सरलीकरण केवल एक बार लिखा गया भयानक अभिव्यक्ति होने से सरलीकरण बहुत फायदेमंद है, ऐसा लगता है। मैं निश्चित रूप से उस कार्यक्रम को मूल की तुलना में बनाए रखना चाहता हूं।

संबंधित मुद्दे