2015-12-09 2 views
1

Ниже приведен код, я использую для чтения и значение массива печати Struct - Я получаю сообщение об ошибке при чтении строки:зсап строка - с языком

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

struct addressbook{ 
    char *fname; 
    char *lname; 
    char *num; 
    char *email; 
}; 

int main() { 
    struct addressbook addr[100]; 
    int add=0,m=0; 
    while (m<3) 
    { 
     printf("1. Show All Entries\n"); 
     printf("2. Add Entry\n"); 
     printf("3. Quit\n"); 
     scanf("%d",&m); 
     if (m==1) 
     { 
      int i; 
      for (i=0; i<add;i++) 
      { 
       printf("FName: %s , LName: %s , Number: %s , Email: %s \n",&addr[i].fname, &addr[i].lname,&addr[i].num,&addr[i].email); 
      } 
     } 
     else if (m==2) 
     { 
      if (add<101) 
      { 
       struct addressbook a; 
       printf("Enter First Name: "); 
       scanf(" %s", &a.fname); 
       printf("Enter last Name: "); 
       scanf(" %s", &a.lname); 
       printf("Enter Contact Number: "); 
       scanf(" %s", &a.num); 
       printf("Enter Email: "); 
       scanf(" %s", &a.email); 
       addr[add] = a; 
       add=add+1; 
      } 
      else{printf("100 limit reached");} 

     } 
     else if (m=3) 
     { 
      m=3; 
     } 
     else 
     { 
      m=0; 
      printf("Invalid option"); 
     } 
    } 
} 

Это основная программа - но она становится закрыт с неизвестной ошибкой. enter image description here

Если длина строки вводится в виде всего 3 символов, то ошибки не возникает. Не могли бы вы исправить меня, где я ошибся.

Пробовал ниже код тоже пока не работает

printf("Enter First Name: "); 
       scanf(" %s", &addr[add].fname); 
       printf("Enter last Name: "); 
       scanf(" %s", &addr[add].lname); 
       printf("Enter Contact Number: "); 
       scanf(" %s", &addr[add].num); 
       printf("Enter Email: "); 
       scanf(" %s", &addr[add].email); 
       add=add+1; 
+0

scanf ("% s", & a.fname); <- 'a.fname' является указателем, поэтому он пытается прочитать строку в указатель? – immibis

+3

Ни одно из ваших структурных полей не будет правильно инициализировано.На самом деле они не инициализируются вообще. Поэтому вы не можете использовать их в 'scanf'. 'scanf' не выделяет вам память. Вам нужно указать правильные буферы для записи. – kaylum

+1

Это неопределенное поведение. Вы не выделяете память для этих указателей. Еще хуже то, что вы на самом деле не пишете в памяти, на которые они указывают, но записывают строки в фактический указатель – paddy

ответ

2

Давайте предположим, что это 32-битная система, поэтому указатели по 4 байта. Ваш addressbook структура выглядит в памяти:

0 1 2 3 4 5 6 7 8 9 A B C D E F 
    --------------------------------- 
    [fname ][lname ][num ][email ] 

При объявлении локальной переменной struct addressbook a;, это именно то, что вы получите в стеке - 16 байт неинициализированной памяти:

0 1 2 3 4 5 6 7 8 9 A B C D E F 
    --------------------------------- 
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 

И теперь вы начинаете считать фактическое значение указателя с scanf. Вот что ваша структура выглядит как после первого ввода:

0 1 2 3 4 5 6 7 8 9 A B C D E F 
    ---------------------------------- 
    a s d a s d a \0 ? ? ? ? ? ? ? ? 

И после последнего ввода:

0 1 2 3 4 5 6 7 8 9 A B C D E F * * * * * * 
    --------------------------------------------- 
    a s d a c a s c 1 2 3 1 a s d a s d a s d \0 

Упс! Таким образом, вы написали 6 дополнительных байт памяти с конца вашей структуры, которая поглощает все остальное в вашем стеке. Теперь это может быть только . были переменными add и m, которые теперь представляют собой огромное значение. Затем вы пишете addr[add] и BOOM - вы только что записали в память где-то вне вашего стека.

Это один сценарий. На самом деле все могло случиться. Дело в том, что это неопределенное поведение, и вам следует избегать этого любой ценой!

Что делать? Ну, есть большие темы об этом везде, и почему scanf is BAD для чтения строк в первую очередь. Но в крайнем случае, давайте предположим, что ваши пользователи ведут себя сами. Если вы просто изменить эти указатели на массивы, жизнь наладится:

/* Arbitrary string length limits */ 
#define MAX_FNAME 20 
#define MAX_LNAME 20 
#define MAX_NUM 20 
#define MAX_EMAIL 50 

struct addressbook{ 
    char fname[MAX_FNAME]; 
    char lname[MAX_LNAME]; 
    char num[MAX_NUM]; 
    char email[MAX_EMAIL]; 
}; 

И теперь вы убедитесь, что вы используете правильный указатель при вызове scanf. Если вы используете a.fname, компилятор распадет массив на указатель, поэтому вы не должны пройти &a.fname. Вы либо написать a.fname или &a.fname[0]:

scanf(" %s", a.fname); 

Это не единственное решение, конечно. И это уже небезопасно. Но я не хочу подавлять вас слишком большой информацией на данный момент. Надеюсь, это было полезным началом. Будьте осторожны, хорошо ?! =)

+0

Это некоторые Большое спасибо. Вам нужно многому научиться - VB намного проще, чем это :( – surpavan

+0

Не волнуйтесь, VB может быть проще, но никто не реализует операционные системы, драйверы устройств или серьезные компиляторы с VB. Начните думать о том, как ваша программа действительно выполняет свою задачу на процессоре. Если вы хотите более выразительный и одинаково мощный язык, вы можете изучить C++. Но пока просто расслабьтесь и получите удовольствие от этой новой потрясающей силы, с которой вы обладаете язык C. Вы скоро поймете, что он ударяет по прикладу VB. – paddy