У вас есть две большие проблемы с 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
Посмотрите вещи и дайте мне знать если у вас есть вопросы.
Повторитесь после меня: Все хорошие программисты VB используют Option Explicit
Это сохранит Вас от случайного объявления новой переменной и использования его - таким образом отбрасывающий независимо от того, что Вы делаете.
Кроме того, это зависит от того, что Вы делаете.
Остерегайтесь каждый раз, когда Вы видите следующую строку:
On Error Resume Next
Это было бы моей осторожностью в использовании классического ASP.
Условные выражения время от времени немного неинтуитивны.
Например, при контакте с Null
s: Хотя True
и Null
не равны, следующее выражение будет действовать как False
. В этом случае хорошо проверить на Null
явно использование IsNull
.
valueIsTrue = True
valueIsNull = Null
If valueIsTrue <> valueIsNull Then ...
Кроме того, в отличие от некоторых других языков, оценены все части условия, даже если первая часть False
. Например, следующий пример возвратил бы ошибку если myObject
были Nothing
:
If Not IsNothing(myObject) And myObject.IsValid() Then ...
Решение состоит в том, чтобы разделить вложенное использование условий If
s или некоторые другие средства:
If Not IsNothing(myObject) Then
If myObject.IsValid() Then
...
Общий Глюк, когда использование HTML-форм является несоответствием между CharSet страницы формы и CodePage страницы получения.
Типичный пример - то, где страница Form устанавливает свой CodePage на 65 001 и ответ CharSet к UTF-8. Это вызывает любые значения, ввел в форму, которая будет отправлена назад с помощью кодировки UTF-8. Страница получения уезжает, ее CodePage устанавливают Систему кодовая страница OEM такой 1252.
Противостоите интуитивно использованию ASP Ответ. CodePage, чтобы определить, как символы в сообщении формы должны быть интерпретированы, следовательно кодировка UTF-8, ошибочно принят как набор ot 1 252 символа, повреждающие вход.
Иногда это идет необнаруженное, потому что страница отвечает, устанавливает его Reponse. CharSet к UTF-8, но оставляет свой CodePage без изменений. Результат пользователю кажется хорошим, но данные ввели в базу данных, повреждено.
Моей рекомендацией является Сохранение как UTF-8, используйте @codepage = 65001 на всех страницах и всегда устанавливайте Ответ. CharSet к UTF-8. Это покрывает все.
VBScript имеет nastly способ позволить Вам назвать нижние индексы с круглой скобкой, если у Вас только есть 1 параметр. Однако, если та парамать передается ссылкой, возвращаемое значение не выходит при использовании круглой скобки:
<% OPTION EXPLICIT %>
<%
sub MakeLonger(byref something)
something = "hello " & something
end sub
dim msg
msg = "World"
MakeLonger(msg)
response.write msg
response.write "<br />"
MakeLonger msg
response.write msg
%>
Вывод:
World
hello World
Удостоверьтесь, что Вы используете Set
для ссылок на объект:
Dim rs : Set rs = CreateObject("ADODB.Recordset");
Если Вы не сделаете то Вы или получите недопустимую ссылку на переменную или свойство по умолчанию
Dim field : Set field = rs(0)
Dim fieldValue : fieldValue = rs(0) 'Same as field.Value
Можно не учесть круглую скобку, когда передающие аргументы функциям, но только если вызов функции является единственным выражением в операторе:
DoSomething withThisArgument
Dim result : result = DoSomething(withThisArgument)
result = DoSomething withThisArgument 'SYNTAX ERROR
Выделение автоматической переменной является, вероятно, одним из самых больших глюков.
Dim varA, varB
varA = varA + varV
Ой! Что varV
Вы спрашиваете? Хорошо.. Я просто ввел B с опечаткой для V, и все все еще работает отлично.. это должно быть хорошей вещью!
Разве кроме того, почему varB не, добавляется к варе?? Это должно быть ошибкой Microsoft!
классический ASP имеет много глюков, если бы Вы никогда не работали с ним то :) я рекомендовал бы взглянуть на ajaxed библиотеку, которая является все еще сохраняемой классической библиотекой asp. Это помогает Вам избавиться от наиболее распространенных глюков при контакте с приложениями прежней версии.