Προς το περιεχόμενο
  • 0
maniac89

απορία σε απλό κώδικα στην C με struct

Ερώτηση

>
#include <stdio.h>

struct str
{
    char *name;
};
void main()
{
    struct str s;
    scanf("%s",s.name);
    printf("%s\n",s.name);
}

 

στον παραπάνω κώδικα γιατί μου βγαζει Segmentation Fault.

Αυτό που θέλω να κάνω είναι να διαβάσω ένα όνομα και να το αποθηκεύσω στο πεδίο name

του struct.

Ευχαριστώ πολύ!

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες

15 απαντήσεις σε αυτή την ερώτηση

Προτεινόμενες αναρτήσεις

  • 0

Γιατι δεν εχεις δεσμευσει μνημη για το string.Αν τη μεταβλητη name τη κανεις πινακα,δεν θα εχεις προβλημα

  • Like 1

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

>
#include <stdio.h>

struct str
{
    char name[50];
};
void main()
{
    struct str s;
    scanf("%s",s.name);
    printf("%s\n",s.name);
}

 

τώρα δουλεύει!

έχω μπερδευτεί λίγο με pointers, νόμιζα ότι δέσμευε αυτόματα μνήμη.

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Πρέπει είτε να ορίσεις το name στατικά με συγκεκριμένο μέγεθος...

 

>char name[100+1] = {'\0'}

 

είτε να το κάνεις δυναμικά malloc() πριν επιχειρήσεις να διαβάσεις κάτι μέσα του...

 

>if ( NULL == (name=calloc(100+1, sizeof(char)) ) exit(1);

 

και πριν τερματίσεις το πρόγραμμά σου να το απελευθερώσεις με...

 

>if (name) free(name);

 

Τα παραπάνω χωρίς να είναι σε struct το name. Προσάρμοσέ το στο struct εσύ.

 

EDIT: Και οι 3 μαζί γράφαμε :lol:

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Use gets() instant of scanf()

>
#include "stdafx.h"
#include <malloc.h>
#include <stdlib.h>

typedef struct
{
   char *Name;
   int Age;
   int Weight;
}Person;

#define Length 100

int _tmain(int argc, _TCHAR* argv[])
{
   Person P;

   P.Name = (char *) malloc(sizeof(char *) * Length);
   if (P.Name == NULL)
   exit(1);

   // Initial vars, dont ask (is boring)
   P.Age = 20;
   P.Weight = 100;

   // Read from keyboard
   printf("Enter your name: ");
   gets(P.Name);

   // Print
   printf("I' am %s, i am %d years old and im only %d pounds \n", P.Name, P.Age, P.Weight );

   if (P.Name != NULL)
   free(P.Name);

   return 0;
}

  • Like 1

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

@Latency:

 

Χρειάζονται πολύ περισσότερα για να διαβαστεί με ασφάλεια ένα string από την κύρια είσοδο, στην C. Η gets() btw απαγορεύεται δια ροπάλου, επειδή δεν σε αφήνει να ελέγξεις πόσους χαρακτήρες διαβάζεις (αν στο παράδειγμά σου σου δώσουν π.χ. 102 χαρακτήρες για όνομα θα κρασάρει)... είναι από τους λόγους που ήταν ήδη depreciated στην C99 και καταργήθηκε πλήρως στην C11.

 

Use fgets() instead.

 

Επίσης, το malloc() που κάνεις δεν θέλει αστερίσκο στο sizeof()... έτσι όπως το 'χεις τώρα δεσμεύεις length δείκτες σε char, αντί για length chars που θέλεις (επίσης δεν χρειάζεται καν το cast, εκτός αν μιλάμε για πολύ εξειδικευμένη πλατφόρμα, που ξέρω γω χρησιμοποιεί K&R C)

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

>
#include <stdio.h>

struct str
{
 char name[50];
};
void main()
{
 struct str s;
 scanf("%s",s.name);
 printf("%s\n",s.name);
}

 

τώρα δουλεύει!

έχω μπερδευτεί λίγο με pointers, νόμιζα ότι δέσμευε αυτόματα μνήμη.

 

σε αυτό το παράδειγμα δουλεύει γιατί έχεις πίνακα και δεσμεύει από μόνο του μνήμη, στο προηγούμενο είχες έναν δείκτη και ως γνωστός πρέπει μόνος σου να δεσμεύσεις μνήμη

 

ο ρόλος του "Length" ουσιαστικά είναι πόσους χαρακτήρες παίρνει, δηλαδή δεσμεύει μνήμη για 100 χαρακτήρες στο συγκεκριμένο παράδειγμα, υπολόγισε -1 συνέχεια για τον τερματικό χαρακτήρα, άρα 99 μπορείς να χρησιμοποιήσεις...

 

@Latency:

 

Χρειάζονται πολύ περισσότερα για να διαβαστεί με ασφάλεια ένα string από την κύρια είσοδο, στην C. Η gets() btw απαγορεύεται δια ροπάλου, επειδή δεν σε αφήνει να ελέγξεις πόσους χαρακτήρες διαβάζεις (αν στο παράδειγμά σου σου δώσουν π.χ. 102 χαρακτήρες για όνομα θα κρασάρει)... είναι από τους λόγους που ήταν ήδη depreciated στην C99 και καταργήθηκε πλήρως στην C11.

 

Use fgets() instead.

 

Επίσης, το malloc() που κάνεις δεν θέλει αστερίσκο στο sizeof()... έτσι όπως το 'χεις τώρα δεσμεύεις length δείκτες σε char, αντί για length chars που θέλεις (επίσης δεν χρειάζεται καν το cast, εκτός αν μιλάμε για πολύ εξειδικευμένη πλατφόρμα, που ξέρω γω χρησιμοποιεί K&R C)

 

μου κάνει εντύπωση που δεν χτυπάει, μπορείς να δεσμεύσεις για 5 χαρακτήρες και να γράψεις 50, μόνο όταν αφήνεις κενά χτυπάει,

 

δηλαδή αν δηλώσεις Length 2 και γράψεις one two θα το πάρει, αν γράψεις onetwothreefore θα το πάρει, αν γράψεις one two three χτυπάει

 

αντί να διαβάζει χαρακτήρες διαβάζει ομάδες...

 

ohh τώρα το είδα

 

>
P.Name = (char *) malloc(sizeof(char *) * Length);

 

@τοπικ σταρτερ, το παραπάνω θέλει αλλαγή σε

>
P.Name = (char *) malloc(sizeof(char) * Length);

 

@παπι

όπως είπα όταν παίζεις με δυναμική δέσμευση μνήμης τα ξέρεις αυτά, μπορείς να το κάνεις φυσικά να δεσμεύσει επιπλέον αν βγει παραπάνω ...

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

...

@παπι

όπως είπα όταν παίζεις με δυναμική δέσμευση μνήμης τα ξέρεις αυτά, μπορείς να το κάνεις φυσικά να δεσμεύσει επιπλέον αν βγει παραπάνω ...

 

Ή πολύ πιο απλά μπορείς να διαβάζεις με fgets() ώστε να κοντρολάρεις το πλήθος των χαρακτήρων που διαβάζεις.

 

ΥΓ. Υποθέτω εμένα εννοούσες αντί για τον πάπι ;)

 

>
#define MAXINPUT   Whatever
...
char input[ MAXINPUT ] = {'\0'};
...
fgets( input, MAXINPUT, stdin);
// remove '\n' from end if you don't need it
...

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

λες να χρησιμοποίησης ένα προσωρινό αρχείο?

fgets(char *_Buf, int _MaxCount, FILE *_File);

 

ΥΓ: μην γράφετε στα παραδείγματα σας τέτοιο κώδικα

>
if(NULL == Blabla)

 

γιατί απλά μπερδεύει τον κόσμο, ας μάθει ο κόσμος το κανονικό και μετά προχωράει και σε αυτό.

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

Το stdin δεν είναι προσωρινό αρχείο, είναι η κύρια είσοδος.

 

ΥΓ. Δεν ξέρω αν τον μπερδεύει τον κόσμο το να βάζει τις σταθερές πρώτα στις συγκρίσεις, σίγουρα όμως τον προστατεύει από αρκετούς πονοκεφάλους (ιδιαίτερα όταν κάνει τα πρώτα του βήματα).

  • Like 2

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

>
char *pos_term;
pos_term=(char*)malloc(sizeof(char));

 

δεν το χω πιάσει ακόμα! :fear:

αν έχω τον παραπάνω κώδικα ο pos_term είναι σαν ένας πίνακας;

και αν ναι πόσα στοιχεία μπορεί να αποθηκεύσει;

δηλαδή το αντίστοιχο pos_term[ ] ποιό είναι;

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

>
       char name[50];

 

τώρα δουλεύει!

έχω μπερδευτεί λίγο με pointers, νόμιζα ότι δέσμευε αυτόματα μνήμη.

 

Όντως δεσμεύει μνήμη αλλά όχι όπως το φαντάζεσαι. Αν παραβλέψουμε προχωρημένα σενάρια, όταν δηλώνεις μια μεταβλητή, δεσμεύεται στην στοίβα όση μνήμη χρειάζεται για αυτή τη μεταβλητή. Το όνομα της μεταβλητής είναι ένας εύκολος συμβολικός τρόπος να προσπελαύνεις αυτή τη διεύθυνση μνήμης.

 

>
1) int i;
2) float f[5];
3) char *p;

Σύμφωνα με αυτό που είπαμε, στην 1η περίπτωση δεσμεύεται μνήμη για ένα int και έτσι μπορείς και χρησιμοποιείς κανονικά το i. Στη 2η περίπτωση δεσμεύεται μνήμη συνεχόμενα για 5 floats. Στην 3η περίπτωση έχουμε ένα δείκτη οπότε δεσμεύεται όση μνήμη χρειάζεται για ένα δείκτη. Αυτή η διεύθυνση που δεσμεύτηκε μπορεί να χρησιμοποιηθεί κανονικά. Όπως δηλαδή λες i = 5, μπορείς να γράψεις μια τιμή σε αυτή τη διεύθυνση. Η τιμή αυτή όμως που θα γράψεις για να μπορεί να προσπελαστεί θα πρέπει να είναι διεύθυνση που έχει δωθεί στο πρόγραμμά σου, για αυτό και έπρεπε να δεσμεύσεις και άλλη μνήμη. Μπορείς δηλαδή να γράψεις p = 5 αλλά επειδή η διεύθυνση 5 δεν ανήκει στο πρόγραμμά σου δεν μπορείς να γράψεις *p = 12.

 

>
char *pos_term;
pos_term=(char*)malloc(sizeof(char));

 

δεν το χω πιάσει ακόμα! :fear:

αν έχω τον παραπάνω κώδικα ο pos_term είναι σαν ένας πίνακας;

και αν ναι πόσα στοιχεία μπορεί να αποθηκεύσει;

δηλαδή το αντίστοιχο pos_term[ ] ποιό είναι;

Οι παραπάνω εντολές δηλώνουν ένα δείκτη σε char και μετά του εκχωρούν μνήμη μεγέθους ενός char οπότε μπορείς να χρησιμοποιήσεις τον δείκτη pos_term για να αποθηκεύσεις μία τιμή char (πχ *pos_term = 19). Αν έγραφες malloc(13) θα δέσμευες μνήμη μεγέθους 13 char και τότε θα ήταν σαν να είναι πίνακας που είπες.

 

  • Like 1

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

ok, ευχαριστώ για την βοήθεια!

Τώρα θέλω να διαβάσω από ένα αρχείο ένα string και να το αποθηκεύσω στon *pos_term.

Ενώ κάνω μόνο malloc για ένα char

>
pos_term=(char*)malloc(sizeof(char));

τρέχει κανονικά και αποθηκεύει και τεράστιες λέξεις.

Από ότι κατάλαβα αυτό είναι σαν να αποθηκεύεται στην πρώτη θέση ενός "πίνακα".

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

ok, ευχαριστώ για την βοήθεια!

Τώρα θέλω να διαβάσω από ένα αρχείο ένα string και να το αποθηκεύσω στon *pos_term.

Ενώ κάνω μόνο malloc για ένα char

>
pos_term=(char*)malloc(sizeof(char));

τρέχει κανονικά και αποθηκεύει και τεράστιες λέξεις.

Από ότι κατάλαβα αυτό είναι σαν να αποθηκεύεται στην πρώτη θέση ενός "πίνακα".

 

Θα σου "χτυπήσει" segmentation fault στο run-time, αν και όταν το πρόγραμμά σου επιχειρήσει να χρησιμοποιήσει την έξτρα μνήμη που έχει καταχραστεί το stream-input του προγράμματός σου (δηλαδή οτιδήποτε βρίσκεται δίπλα στον 1 χαρακτήρα που έχεις δεσμεύσει με αυτό το malloc() )

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες
  • 0

ok, ευχαριστώ για την βοήθεια!

Τώρα θέλω να διαβάσω από ένα αρχείο ένα string και να το αποθηκεύσω στon *pos_term.

Ενώ κάνω μόνο malloc για ένα char

>
pos_term=(char*)malloc(sizeof(char));

τρέχει κανονικά και αποθηκεύει και τεράστιες λέξεις.

Από ότι κατάλαβα αυτό είναι σαν να αποθηκεύεται στην πρώτη θέση ενός "πίνακα".

 

Αυτό είναι πλάγιο πλεονέκτημα του πως δουλεύουν οι περισσότεροι allocators.

 

Καταρχήν να πούμε πως όταν δεσμεύεις μνήμη για ένα char, κανείς δεν σε εμποδίζει να πας να γράψεις 5 θέσεις μετά γιατί η C δεν έχει έλεγχο ορίων. Όταν τώρα ζητάς ένα μέγεθος μνήμης, οι περισσότεροι allocators σου δίνουν παραπάνω μνήμη από αυτή που ζητάς. Για παράδειγμα μπορεί εσύ να ζητήσεις 1 byte και να σου δώσει 16. Ένα άλλο σενάριο είναι να έχεις δεσμεύει μνήμη για πολλές μεταβλητές και αυτή να είναι συνεχόμενη οπότε όταν πας να γράψεις έξω από την 1η να πέφτεις στον χώρο της 2ης.

 

Έτσι μπορεί 5 φορές από τις 10 που τρέχεις το πρόγραμμα να φαίνεται ότι λειτουργεί σωστά (στη πραγματικότητα όμως _δεν_ λειτουργεί σωστά) και τις άλλες 5 να χτυπάει όπως σου είπε ο migf1.

  • Like 1

Κοινοποιήστε αυτήν την ανάρτηση


Σύνδεσμος στην ανάρτηση
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε έναν λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι εύκολο!

Εγγραφείτε για έναν νέο λογαριασμό

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
×
×
  • Δημιουργία νέου...

Χρήσιμες πληροφορίες

Με την περιήγησή σας στο insomnia.gr, αποδέχεστε τη χρήση cookies που ενισχύουν σημαντικά την εμπειρία χρήσης.