¿Cuál es la diferencia entre Delphi TStringList y String?
Es un tipo de lista de cadenas, administrado por el sistema PASCAL y utilizado como una matriz, pero su tamaño es dinámico, es decir, se implementa esencialmente mediante una lista vinculada, basada en una lista vinculada estructura de datos. Esto es algo común, que a menudo se usa para organizar una cadena de cadenas, es decir, datos de tipo cadena. Hay muchas discusiones sobre el uso de TStrigList en Internet, que se pueden descargar de Baidu.
Cadena es un tipo de datos que almacena cadenas.
Introducción a los principios de los tipos de cadenas en Delphi
La operación de cadenas en Delphi es muy simple, pero la situación detrás de escena es bastante complicada. El método tradicional de operación de cadenas de Pascal es diferente al de Windows. Absorbe el método de operación de cadenas del lenguaje C. El tipo de cadena larga se ha agregado a Delphi de 32 bits. Este tipo es potente y es el tipo de cadena predeterminado de Delphi.
Tipo de cadena En TurboPascal de Borland y Delphi de 16 bits, el tipo de cadena tradicional es una secuencia de caracteres, y el encabezado de la secuencia es un byte de longitud, que indica la longitud de la cadena actual. Dado que solo se utiliza un byte para representar la longitud de la cadena, la cadena no puede exceder los 255 caracteres. Este límite de longitud es inconveniente para las operaciones de cadenas, porque la longitud de cada cadena debe ser fija (el valor máximo es 255); por supuesto, también puede declarar cadenas más cortas para ahorrar espacio de almacenamiento.
Los tipos de cadenas son similares a los tipos de matrices. El hecho de que una cadena sea casi una matriz de tipos de caracteres, por lo que puede usar la notación [] para acceder a los caracteres de una cadena, dice mucho del punto anterior.
Para superar las limitaciones de las cadenas Pascal tradicionales, Delphi de 32 bits añade soporte para cadenas largas. Entonces * * * hay tres tipos de cadenas:
Cadenas cortas
El tipo de cadena corta es también el tipo de cadena Pascal tradicional mencionado anteriormente. Estas cadenas sólo pueden tener hasta 255 caracteres, lo mismo que las cadenas en Delphi de 16 bits. Cada carácter de una cadena corta es de tipo ANSIChar (tipo de carácter estándar).
Asignación
El tipo de cadena larga es un tipo de cadena de longitud variable recién agregado. Esta cadena se asigna dinámicamente desde la memoria y utiliza recuento de referencias, utilizando tecnología de copia en escritura. No hay límite para la longitud de esta cadena (¡puede almacenar hasta 2 mil millones de caracteres!) y su tipo de carácter también es ANSIChar.
WideChar
Tipo de cadena larga y asignación
El tipo es similar excepto que se basa en el tipo de carácter WideChar (carácter Unicode de doble byte).
Usar cadenas largas
Si una cadena se define simplemente como una cadena, puede ser una cadena corta o una cadena larga ANSI, dependiendo del valor de la directiva de compilación $H. $H+ (provincia exacta) representa una cadena larga (tipo ANSIString). Las cadenas largas son las cadenas utilizadas por los controles en la biblioteca Delphi.
La cadena larga de Delphi se basa en el mecanismo de conteo de referencias, que utiliza el conteo de referencias para rastrear variables de cadena en la memoria que hacen referencia a la misma cadena y libera la memoria cuando la cadena ya no se usa, es decir, cuando el recuento de referencia llega a cero.
Si quieres aumentar la longitud de una cadena y no hay memoria libre cerca de la cadena, es decir, no hay espacio para extender la cadena en la misma unidad de almacenamiento, debes copiar la cadena por completo a otra unidad de almacenamiento. Cuando esto sucede, el programa de soporte de tiempo de ejecución de Delphi reasignará la memoria para la cadena de una manera completamente transparente. Para asignar eficientemente el espacio de almacenamiento requerido, puede utilizar el procedimiento SetLength para establecer la longitud máxima de una cadena, por ejemplo:
SetLength
(String1,
200);
El proceso SetLength solo completa una solicitud de memoria y en realidad no asigna memoria. Simplemente reserva la memoria que se necesitará en el futuro, pero en realidad no la utiliza.
Esta tecnología se originó en el sistema operativo Windows y ahora Delphi la utiliza para asignar memoria dinámicamente. Por ejemplo, cuando solicita una matriz grande, el sistema reserva memoria de la matriz, pero la memoria no se asigna a la matriz.
Normalmente, no es necesario establecer la longitud de la cadena, pero cuando necesita pasar una cadena larga como parámetro a una función API (después de la conversión de tipo), debe usar SetLength para eso. Las cadenas de caracteres reservan espacio en la memoria, lo explicaré más adelante.
Eche un vistazo a las cadenas en la memoria
Para ayudarlo a comprender mejor los detalles de administración de memoria de las cadenas, escribí un ejemplo simple StrRef. En el programa declaro dos cadenas completas: Str1 y Str2. Cuando se presiona el primer botón, el programa asigna una constante de cadena a la primera variable y luego asigna la primera variable a la segunda variable:
Str1
:=
'Hola';
Str2
:=
str 1;
Excepto caracteres Además de la manipulación de cadenas, el El programa utiliza la siguiente función StringStatus para mostrar el estado interno de una cadena en un cuadro de lista:
Función
Estado de la cadena
(constante
Str:
String):
String;
Inicio
Resultado
:= p>
Dirección:
'
+
IntToStr
(entero
(Str) )
+
,
Longitud:
'
+
IntToStr
(Longitud
(Str))
+
,
Referencias:
'
+
IntToStr
(PintToStr
(Entero
(Str)
-
8)^)
+
,
Valor:
'
+
Str
End;
En la función StringStatus, pase la constante La cadena del parámetro es muy importante. Pasar por copia (parámetro de valor) tendrá efectos secundarios porque se generará una referencia adicional a la cadena durante la ejecución de la función; por el contrario, pasar por parámetro de referencia (var) o constante (const) no producirá esta situación; Como en este ejemplo no se desea modificar la cadena, se eligieron argumentos constantes.
Para obtener la dirección de memoria de la cadena (esto ayuda a identificar el contenido real de la cadena y observar si dos variables de cadena diferentes se refieren a la misma área de memoria), escribo la cadena a través de un mapa de tipos. Transmitir a un número entero. Una cadena es en realidad una referencia, un puntero: una variable de cadena contiene la dirección de memoria real de la cadena.
Para extraer la información del recuento de referencias, aproveché un hecho poco conocido: la longitud de la cadena y la información del recuento de referencias en realidad se almacenan en la cadena, en la ubicación de memoria señalada por el contenido y la cadena reales. variables delante de, el desplazamiento negativo de la longitud de la cadena es -4 (este valor se obtiene fácilmente usando la función Longitud) y el desplazamiento negativo del recuento de referencia es -8.
Sin embargo, debe recordarse que la información interna anterior sobre compensaciones puede cambiar en futuras versiones de Delphi, y es difícil garantizar que la funcionalidad no escrita en la documentación oficial de Delphi permanecerá sin cambios en el futuro.
Al ejecutar este ejemplo, verá que las dos cadenas tienen el mismo contenido, la misma ubicación de memoria y un recuento de referencias de 2, como se muestra en la parte superior del cuadro de lista en la Figura 7.1. Ahora, si cambia el valor de una de las cadenas, la dirección de memoria de la cadena actualizada también cambiará. Esto es el resultado de la tecnología de copia sobre escritura.
El código de evento OnClick del segundo botón (Cambiar) es el siguiente, y el resultado se muestra en la segunda parte del cuadro de lista 7.1:
Programa
TFormStrRef.
BtnChangeClick(remitente:
al asunto);
Inicio
Str1
[2]
:=
'a';
Cuadro de lista 1. proyecto. Añadir
('str 1
[2]
:=
''a'');
Cuadro de lista 1. proyecto. Añadir
('str 1
-
+
Estado de cadena
(str 1));
Cuadro de lista 1. proyecto. Añadir
(Str2
-
'
+
Estado de la cadena
(str 2);
End;
Tenga en cuenta que BtnChangeClick solo se puede ejecutar después de ejecutar BtnAssignClick, por lo que el segundo botón (la propiedad Enabled del botón) no se puede usar después el programa se ha iniciado. Establecido en False); activa el segundo botón después de que finaliza el primer método. Puede ampliar este ejemplo y utilizar la función StringStatus en otras situaciones para explorar las características de las cadenas largas. Se puede utilizar cualquier función de asignación de memoria.
De hecho, el sistema eventualmente llama a GetMem
Otro Nuevo, AllocMem, SetLength, etc. Además de llamar a GetMem, como borrar la memoria, se puede usar Dispose o FreeMem
El sistema finalmente llama a FreeMem
Dispose es equivalente a Finalize(p); /p>
FreeMem( p);
La función de Finalize es liberar automáticamente cadenas y matrices dinámicas en estructuras o matrices.
FreeMem libera directamente la memoria a la que apunta. el puntero, por ejemplo:
Tipo
TMyRec
=
Registro
Nombre: p>
Cadena;
x,
y:
Entero;
Fin
PMyRec
=
^tmyrec;
Definir variables
MyRec
:
PMyRec
Inicio
p>Nuevo (MyRec);
//
El compilador calculará automáticamente la cantidad de memoria a se asignará según el tamaño de MyRec y luego generará código para llamar a GetMem y borrarlo. Campo de nombre
nombre de Myrek
:=
str1
+
str2
Disposición (MyRec);
//
Además de llamar a FreeMem para liberar el memoria de la estructura MyRec, la memoria utilizada por Nombre también se borrará automáticamente (si Nombre apunta al recuento de referencias de cadena = 1);
//
FreeMem(MyRec);
& lt-
Si llamas a FreeMem directamente para liberar MyRec,
Esto causará una pérdida de memoria,
porque Myrec apunta al cadena. El nombre no está publicado (recuento de referencias -1).
Fin;
Debido a la particularidad de la gestión de memoria de cadenas de Delphi,
Existen muchas técnicas que pueden aprovecharla al máximo para generar código muy eficiente. .
Por ejemplo, para usar TList para guardar cadenas (en lugar de TStringList),
El enfoque habitual es guardar un puntero PString en TList. Proyecto [I].
Por lo tanto, es necesario reasignar una parte de la memoria y copiar la cadena original.
Es muy ineficiente en el caso de grandes cantidades de datos,
Pero si haces pleno uso del recuento de referencias de cadenas y las habilidades de conversión de tipos,
Puede convertir caracteres directamente. Las cadenas se almacenan como punteros en TList. Proyecto [I]:
Por ejemplo:
Definir variables
Lista:
TList
GlobalString1< / p>
Cadena global 2:
Cadena;
...
Programa
Prueba;
Definir variables
tmp:
Cadena;
Inicio
Programa Terminal Monitor (abreviatura de Terminal Monitor Program) p>
:=
cadena global 6 5438+cadena global 2
Lista. Add(pointer(tmp));
//
Guarde tmp como puntero a la lista.
{
Dado que tmp se libera automáticamente al final del proceso de prueba,
Si sale directamente, el puntero no válido se guardará en la lista.
Así que tenemos que engañar al compilador,
hacerle pensar que tmp ha sido lanzado,
Es equivalente a no cambiar el recuento de referencias de tmp (actualmente 1) En el caso de ejecutar tmp.
:=
'' declaración,
debido al tmp directo
:=
modificará la Recuento de referencias y posiblemente memoria libre.
Así que use cast para convertir tmp a un número entero y establezca el número entero en 0 (es decir, nulo).
Esta declaración es exactamente equivalente al puntero (tmp)
:=
Cero;
Esto es solo una preferencia personal. Me gusta usar números enteros
:=
solo 0.
}
Entero (tmp)
:=
0;
Fin;
1.
El compilador de Delphi admite cadenas internamente (predefinidas
o
integradas), que es un tipo de datos básico de Delphi, PChar. Solo un puntero a una cadena terminada en cero
2.
Línea
La cadena almacenada asigna memoria en el montón y la variable de cadena en realidad es lo anterior. es un puntero a una cadena terminada en cero. Al mismo tiempo, también tiene una función de recuento de referencias (reference
Count) y guarda la longitud de la cadena cuando el recuento de referencias llega a cero. libera el espacio ocupado.
3. Asignar una cadena a otra cadena es solo una simple asignación de puntero, que no produce una acción de copia y solo aumenta el recuento de referencias de la cadena;
4 .Assign PChar tipo de variable a cadena.
El tipo de variable producirá una acción de copia real, es decir, toda la cadena apuntada por PChar se copiará a la memoria asignada para la cadena
5. variable El tipo simplemente asigna el valor del puntero de la cadena al tipo de variable PCCAR. El recuento de referencia de la cadena no cambiará debido a esta operación, porque en este caso PCCAR dependerá de la cadena. PCCAR puede señalar una dirección de memoria no válida cuando el recuento de referencias de la cadena es cero, por lo que debe tener cuidado al manejar esta situación en su programa.
6. PCCar se ejecuta mucho más rápido que string, pero PCCar es una forma retrógrada de gestionar strings, mientras que string gana con una gestión eficiente. PCCar existe sólo por compatibilidad con tipos y sistemas operativos anteriores (llamados Windows).
Utilizado con frecuencia en API), se recomienda utilizar cadenas normalmente.