Объект Query
при запросе на итерацию результатов, представляющих объект, подобный TestSet
, выполняет идентификацию в результирующих строках на основе идентификатора объекта, так что если запрос должен был возвращать 100 строк, каждый с тем же TestSet
, вы получите только один объект результата. Это поведение проистекает из функции «горячего присоединения» Query
, где часто бывает, что многие строки результатов получаются с одинаковым первичным идентификатором, но также содержат переменную вторичную идентификацию соответствующей строки, которая должна быть заполняется в коллекцию по каждой первичной идентичности - в этом очень распространенном случае желательно только один экземпляр первичного идентификатора.
Давайте рассмотрим, что делает distinct()
. Предположим, что ваш запрос для объектов 4M возвращает 1000 строк с id = 1, 1000 строк с id = 2 и т. Д. Запрос с лимитом (100) попадает в первые 100 строк с id = 1, Query
uniquifies, и вы получаете один результат объект назад, так как все они id = 1. Но с distinct()
внезапно мы получаем 100 строк с различными тождествами, то есть «id = 1», «id = 2», «id = 3». Query
затем присваивает каждой из этих строк новому TestSet
объекту в карте идентификации, и вы получите 100 строк назад.
Параметр echo='debug'
на вашем Engine
временно покажет, что SQL является а также возвращаемые строки результатов. Когда вы видите много строк результатов с одним и тем же первичным ключом, вы знаете, что Query
, когда его попросят вернуть полные объекты, будет уникальным для всех этих избыточных тождеств до одного объекта, представленного для каждой строки.
Здесь вы объявляете headptr
и устанавливаете его на NULL
:
struct record *headptr = NULL;
Затем вы передаете его insert
:
insert(headptr, data);
Итак, ptr
в insert
равно NULL
:
void insert(struct record *ptr, int value)
Затем вы устанавливаете curptr = ptr;
, поэтому curptr
равно NULL
. Затем происходит сбой в этой строке:
while (value >= (curptr->data)) {
Поскольку вы пытаетесь получить доступ к памяти, на которую указывает curptr
, то есть NULL
на тот момент.
Я предполагаю, что вы хотели выделить память для headptr
перед передачей ее в insert
. Или обработайте регистр указателя как NULL
в insert
.
Во-первых, используйте setbuf(stdout, NULL);
, если вы хотите, чтобы ваши отпечатки сбрасывались до того, как ваша программа неожиданно завершит работу.
Во-вторых, как уже упоминали другие, вы получаете доступ к элементу указателя NULL
в while (value >= (curptr->data))
, который вызывает сбой.
В-третьих, ваша insert
и print
логика также неверна.
#include <stdio.h>
#include <stdlib.h>
struct record{
int data;
struct record *nextptr;
};
void insert (struct record **ptr,int value);
void printList(struct record *ptr);
int main() {
setbuf(stdout, NULL);
struct record *headptr = NULL;
for (int i = 0; i < 4; ++i) {
int data;
printf("Enter your value");
scanf("%d", &data);
insert(&headptr, data);
}
printList(headptr);
return 0;
}
void insert (struct record **head,int value){
printf("WE ARE IN THE INSERT FUNCTION");
struct record *newptr = (struct record *) malloc(sizeof(struct record));
newptr->data=value;
newptr->nextptr=NULL;
struct record *curptr=*head;
struct record *prevcurptr=NULL;
while(curptr!=NULL && value >= (curptr->data)){
prevcurptr=curptr;
curptr=curptr->nextptr;
}
if (curptr==NULL){
if (prevcurptr==NULL) {
*head=newptr;
} else {
newptr->nextptr=prevcurptr->nextptr;
prevcurptr->nextptr=newptr;
}
}
else{
newptr->nextptr=curptr;
if (prevcurptr==NULL)
*head=newptr;
else
prevcurptr->nextptr=newptr;
}
}
void printList(struct record *ptr){
while(ptr != NULL){
printf("\n %d", ptr->data);
ptr=ptr->nextptr;
}
}
Если вы передаете указатель на функцию, то, хотя вы можете изменить содержимое того, на что указывает указатель, вы не можете изменить указатель, для этого вам нужно передать указатель на указатель:
[110 ] У вас есть две большие проблемы с insert
. Сначала вы передаете ptr
в качестве указателя struct record
. Когда это происходит, ваша insert
функция получает копию указателя , которая указывает на то же место в памяти, но сама имеет отдельный адрес, очень отличающийся от указателя, переданного из main()
, Что это означает, не имеет значения, что вы делаете с копией указателя в insert
, эти изменения никогда не будут видны в main()
, потому что вы работаете с копией и не возвращаете значение другим способом. Чтобы решить эту проблему, укажите параметр struct record **
и передайте адрес указателя из main()
.
Следующая самая большая проблема, с которой вы столкнулись в insert
, заключается в том, что вы не можете проверить, является ли curptr
NULL
(как это будет при первом вызове insert
), прежде чем вы начнете разыменовывать curptr
- вероятно приводя к segfault или другому запуску мельницы Неопределенное поведение.
При создании связанного списка у вас есть два различных условия тестирования, которые вы должны обработать:
value
из data
. Вы можете обрабатывать оба случая просто:
rec_t *curptr = *ptr,
*newptr = malloc (sizeof *newptr);
if (!newptr) {
perror ("malloc-newptr");
return;
}
newptr->data = value;
newptr->nextptr = NULL;
if (curptr == NULL) { /* handle new-list case and return */
*ptr = newptr;
return;
}
if (value < curptr->data) { /* handle new 1st node */
newptr->nextptr = curptr;
*ptr = newptr;
return;
}
/* iterate with curptr until value > curptr->nextptr->data */
while (curptr->nextptr != NULL && value > curptr->nextptr->data)
curptr = curptr->nextptr;
newptr->nextptr = curptr->nextptr; /* wire new node to next node */
curptr->nextptr = newptr; /* wire current to new node */
В любой программе, которую вы пишете, которая выделяет память, вы должны сохранить указатель на начало каждого выделенного блока, чтобы он мог быть освобожден, когда память больше не нужна. Как правило, вы захотите написать функцию listfree
, чтобы справиться с этим для вас. Вы могли бы написать что-то простое, например:
void freelist (rec_t *head)
{
while (head) {
rec_t *victim = head;
head = head->nextptr;
free (victim);
}
}
( примечание: , как освобождаемый узел сохраняется во временном указателе victim
до того, как список переходит к следующему узлу). ). [одна тысяча сто тридцать одна]
В целом, вы можете сделать что-то вроде следующего:
#include <stdio.h>
#include <stdlib.h>
typedef struct record {
int data;
struct record *nextptr;
} rec_t;
void insert (rec_t **ptr, int value);
void printList (rec_t *ptr);
void freelist (rec_t *head);
int main (void) {
rec_t *headptr = NULL;
for (int i = 0; i < 4; ++i) {
int data;
printf("Enter your value: ");
scanf("%d", &data);
insert (&headptr, data);
}
printList(headptr);
freelist (headptr);
return 0;
}
void insert (rec_t **ptr, int value)
{
if ( ptr == NULL ) {
return;
}
rec_t *curptr = *ptr,
*newptr = malloc (sizeof *newptr); /* don't cast the return */
if (!newptr) {
perror ("malloc-newptr");
return;
}
newptr->data = value;
newptr->nextptr = NULL;
if (curptr == NULL) { /* handle new-list case and return */
*ptr = newptr;
return;
}
if (value < curptr->data) { /* handle new 1st node */
newptr->nextptr = curptr;
*ptr = newptr;
return;
}
/* iterate with curptr until value > curptr->nextptr->data */
while (curptr->nextptr != NULL && value > curptr->nextptr->data)
curptr = curptr->nextptr;
newptr->nextptr = curptr->nextptr; /* wire new node to next node */
curptr->nextptr = newptr; /* wire current to new node */
}
void printList(struct record *ptr)
{
while (ptr != NULL) {
printf(" %d", ptr->data);
ptr = ptr->nextptr;
}
putchar ('\n');
}
void freelist (rec_t *head)
{
while (head) {
rec_t *victim = head;
head = head->nextptr;
free (victim);
}
}
Пример использования / вывода
$ ./bin/lltcmpl
Enter your value: 1
Enter your value: 8
Enter your value: 5
Enter your value: 7
1 5 7 8
$ ./bin/lltcmpl
Enter your value: 2
Enter your value: 1
Enter your value: 4
Enter your value: 3
1 2 3 4
Посмотрите вещи и дайте мне знать если у вас есть вопросы.