Ошибка доступа при логине

222
19 декабря 2016, 19:42
struct account{
    char  login[255];
    char  pass[255];
    char  name[255];
    char  category[255];
};      
int accn=0; 
account    * pacc;
account * npacc;
char cin[255]; //ввод  командной строки 
void addacc(){
    accn++;
    pacc=(account*)realloc(pacc, sizeof(account)*accn);
    npacc=pacc+sizeof(account)*(accn-1);   
    printf("Enter login: "); scanf("%s", &cin); memcpy(&(npacc->login), &cin, 255);
    printf("Enter password: "); scanf("%s", &cin); memcpy(&(npacc->pass), &cin, 255);
    printf("Enter name: "); scanf("%s", &cin); memcpy(&(npacc->name), &cin, 255);
    printf("Enter category name: "); scanf("%s", &cin); memcpy(&(npacc->category), &cin, 255);
    printf("Done!"); enter;
};

При первом вызове addacc() все проходит успешно. При втором выдаёт ошибку после ввода логина.

Answer 1

В строке

npacc=pacc+sizeof(account)*(accn-1);

у вас работает арифметика указателей.

К примеру...

int A;
int *P = &A;

Предположим что переменная А находится по адресу 0. тогда сделав

P = P + 1;

мы получим адрес 4 так как переменная А занимает 4 байта.

А вы берете указатель на структуру и увеличиваете не на 1 что бы перейти к следующей структуре, а на размер структуры. а у неё размер больше 1024байт и поэтому вы в итоге обращаетесь к памяти которая находится на 1024 структуры дальше.

короче я наверно так хорошо вам не объясню, почитайте книжку по С или С++ про арефметику указателей и вам все станет ясно.

Answer 2

@ололо, а зачем Вы лишние операции & пишите? Между прочим, компилятор будет ругаться (warning-ом). Да и выталкивать (fflush) вывод в приглашении и проверять ввод на конец файла не помешает.

Попробуйте что-то в духе

#define enter(prompt,field) (fputs((prompt), stdout), fflush(stdout),   \
                             scanf("%s", (field)))
int addacc(){
    pacc=(account*)realloc(pacc, sizeof(account) * ++accn);
    npacc = pacc + accn - 1;
   int rc = 1;
   if (enter("Enter login: ", npacc->login) != 1 ||
       enter("Enter password: ", npacc->pass) != 1 ||
       enter("Enter name: ", npacc->name) != 1 ||
       enter("Enter category name: ", npacc->category) != 1) {
     --accn;
     rc = 0;
   }
  return rc;
}
....
main () {
...
  while (addacc())
    printf ("account %d : %s %s %s %s\n", accn, pacc[accn-1].login, "", "", "");
...
}

В GNU есть нестандартное расширение, позволяющее "безопасно" читать scanf()-ом по формату %s (см.. man 3 fscanf). Используя его, макрос для ввода поля даннных с заданной максимальной длиной этого поля, можно переписать так (и лучше в виде статической функции)

static inline int  enter(const char *prompt, char *field, int size) 
{
  char *buf; int rc;
  fputs(prompt, stdout); fflush(stdout);
  *field = 0;
  if ((rc = scanf("%as", &buf)) == 1) {
    strncat(field, buf, size);
    free(buf);
  } else 
    rc = 0;
  return rc; 
}
READ ALSO
Прогресс сериализации цепочки классов.

Прогресс сериализации цепочки классов.

Обновил задание на более прикладное: Необходимо выяснить, каков прогресс сериализации объектов классов(ну как полоска загрузки файла с сайта)

201
Произойдёт ли утечка памяти?

Произойдёт ли утечка памяти?

В итоге p1 и p2 будут указывать на один и тот же участок памятиПроизойдёт ли утечка памяти, занятой сначала p1

203
Как правильно формировать criteria для связи HAS_MANY?

Как правильно формировать criteria для связи HAS_MANY?

Есть модель POSTИ есть модель category_r В последней 3 столбца: id, Post_id, category_id

158