Tipos de datos en lenguaje C

En lenguaje C, existe una distinción entre los conceptos de "tipo de datos" y "modificador de tipo". El tipo de datos es entero y el modificador está con o sin signo. Un entero con signo tendrá valores positivos y negativos, mientras que un entero sin signo tendrá sólo valores positivos. Hay cinco tipos básicos en el lenguaje C.

  • char – carácter.
  • Una variable de tipo char tiene un tamaño de 1 byte, sus valores son varios caracteres de la tabla de códigos, por ejemplo: 'f', ':', 'j' (cuando se escriben en el programa, están encerrados en un solo citas).

  • int – entero.
  • El tamaño de una variable de tipo int no está definido en el estándar del lenguaje C. En la mayoría de los sistemas de programación, el tamaño de una variable int corresponde al tamaño de una palabra de máquina completa. Por ejemplo, en compiladores para procesadores de 16 bits, una variable de tipo int tiene un tamaño de 2 bytes. En este caso, los valores con signo de esta variable pueden estar en el rango de -32768 a 32767.

  • flotar – real.
  • La palabra clave float le permite definir variables de tipo real. Sus valores tienen una parte fraccionaria separada por un punto, por ejemplo: -5,6, 31,28, etc. Los números reales también se pueden escribir en forma de coma flotante, por ejemplo: -1,09e+4. El número antes del símbolo "e" se llama mantisa y después de la "e" se llama exponente. Una variable de tipo float ocupa 32 bits en memoria. Puede tomar valores en el rango de 3,4e-38 a 3,4e+38.

  • doble – doble precisión real;
  • La palabra clave double le permite definir una variable real de doble precisión. Ocupa el doble de espacio de memoria que una variable flotante. Una variable de tipo double puede tomar valores en el rango de 1,7e-308 a 1,7e+308.

  • vacío – sin valor.
  • La palabra clave void se utiliza para neutralizar el valor de un objeto, por ejemplo, para declarar una función que no devuelve ningún valor.

Tipos de variables:

Los programas operan con diversos datos, que pueden ser simples o estructurados. Los datos simples son números enteros y reales, símbolos y punteros (direcciones de objetos en la memoria). Los números enteros no tienen parte fraccionaria, pero los números reales sí. Los datos estructurados son matrices y estructuras; se discutirán a continuación.

Una variable es una celda en la memoria de la computadora que tiene un nombre y almacena algún valor. El valor de una variable puede cambiar durante la ejecución del programa. Cuando se escribe un nuevo valor en una celda, el anterior se borra.

Es un buen estilo nombrar las variables de manera significativa. El nombre de la variable puede contener de uno a 32 caracteres. Se permite el uso de letras minúsculas y mayúsculas, números y el guión bajo, que se considera una letra en C. El primer carácter debe ser una letra. El nombre de la variable no puede coincidir con las palabras reservadas.

Escriba carácter

char es el tipo más económico. El tipo de carácter puede estar firmado o sin firmar. Denotado como "carácter firmado" (tipo firmado) y "carácter sin firmar" (tipo sin firmar). El tipo con signo puede almacenar valores en el rango de -128 a +127. Sin signo: de 0 a 255. Se asigna 1 byte de memoria (8 bits) para una variable char.

Las palabras clave con y sin signo indican cómo se interpreta el bit cero de la variable declarada, es decir, si se especifica la palabra clave sin signo, entonces el bit cero se interpreta como parte de un número; de lo contrario, el bit cero se interpreta como con signo.

Escribe entero

El valor entero int puede ser corto o largo. La palabra clave corta se coloca después de las palabras clave firmadas o no firmadas. Entonces hay tipos: int corto con signo, int corto sin signo, int largo con signo, int largo sin signo.

Una variable de tipo int corto con signo (entero corto con signo) puede tomar valores de -32768 a +32767, int corto sin signo (entero corto sin signo), de 0 a 65535. A cada uno de ellos se le asignan exactamente dos bytes de memoria (16 bits).

Al declarar una variable de tipo short int con signo, se pueden omitir las palabras clave con signo y short, y dicho tipo de variable se puede declarar simplemente int. También es posible declarar este tipo con una palabra clave, corta.

Una variable int corta sin signo se puede declarar como int sin signo o como corto sin signo.

Para cada valor de int largo con signo o int largo sin signo, se asignan 4 bytes de memoria (32 bits). Los valores de variables de este tipo pueden estar en los rangos de -2147483648 a 2147483647 y de 0 a 4294967295, respectivamente.

También hay variables del tipo long long int, para las que se asignan 8 bytes de memoria (64 bits). Pueden estar firmados o sin firmar. Para un tipo con signo, el rango de valores es de -9223372036854775808 a 9223372036854775807, para un tipo sin signo, de 0 a 18446744073709551615. Un tipo con signo también se puede declarar simplemente mediante dos palabras clave largas.

Tipo Rango rango hexagonal Tamaño
carácter sin firmar 0 … 255 0x00...0xFF 8 bits
carácter firmado
o simplemente
carbonizarse
-128 … 127 -0x80…0x7F 8 bits
int corto sin firmar
o simplemente
entero sin firmar o corto sin firmar
0 … 65535 0x0000…0xFFFF 16 bits
int corto firmado o firmado int
o simplemente
corto o En t
-32768 … 32767 0x8000…0x7FFF 16 bits
int largo sin firmar
o simplemente
largo sin firmar
0 … 4294967295 0x00000000… 0xFFFFFFFF 32 bits
firmado largo
o simplemente
largo
-2147483648 … 2147483647 0x80000000… 0x7FFFFFFF 32 bits
sin firmar mucho tiempo 0 … 18446744073709551615 0x0000000000000000… 0xFFFFFFFFFFFFFFFF 64 bits
firmado mucho tiempo
o simplemente
largo largo
-9223372036854775808 … 9223372036854775807 0x8000000000000000… 0x7FFFFFFFFFFFFFFFF 64 bits

Declaración de variables

Las variables se declaran en una declaración de declaración. Una declaración consta de una especificación de tipo y una lista de nombres de variables separados por comas. Debe haber un punto y coma al final.

[modificadores] identificador de especificador de tipo [, identificador] ...

Modificadores: palabras clave firmadas, sin firmar, cortas, largas.
Un especificador de tipo es una palabra clave char o int que especifica el tipo de variable que se declara.
El identificador es el nombre de la variable.

Carácter x; ent a, b, c; sin firmar, largo, largo y;

Cuando se declara, una variable se puede inicializar, es decir, se le puede asignar un valor inicial.

Ent x = 100;

Cuando se declara, la variable x contendrá inmediatamente el número 100. Es mejor declarar las variables inicializadas en líneas separadas.

Tipos de datos

Los tipos de datos son especialmente importantes en C# porque es un lenguaje fuertemente tipado. Esto significa que todas las operaciones están sujetas a una estricta verificación de tipos por parte del compilador y las operaciones ilegales no se compilan. En consecuencia, la verificación estricta de tipos elimina errores y aumenta la confiabilidad de los programas. Para imponer la verificación de tipos, todas las variables, expresiones y valores deben ser de un tipo específico. No existe nada parecido a una variable "sin tipo" en este lenguaje de programación. Además, el tipo de valor determina las operaciones que se pueden realizar sobre él. Una operación que es legal para un tipo de datos puede no ser válida para otro.

Hay dos categorías generales de tipos de datos integrados en C#: tipos de valor Y tipos de referencia. Se diferencian en el contenido de la variable. Conceptualmente, la diferencia entre los dos es que un tipo de valor almacena datos directamente, mientras que un tipo de referencia almacena una referencia a un valor.

Estos tipos se almacenan en diferentes ubicaciones de la memoria: los tipos de valor se almacenan en un área conocida como pila y los tipos de referencia se almacenan en un área conocida como montón administrado.

Vamos a ver tipos de valor.

tipos de enteros

C# define nueve tipos de números enteros: char, byte, sbyte, corto, ushort, int, uint, largo y ulong. Pero el tipo char se utiliza principalmente para representar caracteres y, por tanto, se trata por separado. Los ocho tipos de números enteros restantes son para cálculos numéricos. A continuación se muestran su rango de números y profundidad de bits:

Tipos enteros de C#
Tipo Tipo CTS tamaño de bits Rango
byte Sistema.Byte 8 0:255
sbyte Sistema.SByte 8 -128:127
corto Sistema.Int16 16 -32768: 32767
corto Sistema.UInt16 16 0: 65535
En t Sistema.Int32 32 -2147483648: 2147483647
uint Sistema.UInt32 32 0: 4294967295
largo Sistema.Int64 64 -9223372036854775808: 9223372036854775807
ulong Sistema.UInt64 64 0: 18446744073709551615

Como muestra la tabla anterior, C# define variantes con y sin signo de los distintos tipos de enteros. Los tipos de enteros con signo se diferencian de sus homólogos sin signo en la forma en que interpretan el bit más significativo del número entero. Por lo tanto, si un programa especifica un valor entero con signo, el compilador de C# generará código que utiliza el bit más significativo del número entero como indicador de signo. Un número se considera positivo si el signo es 0 y negativo si es 1.

Los números negativos casi siempre se representan mediante el método del complemento a dos, mediante el cual todos los dígitos binarios del número negativo se invierten primero y luego se suma 1 a ese número.

Probablemente el tipo de número entero más común en programación es tipo entero. Las variables de tipo int se utilizan a menudo para control de bucles, indexación de matrices y cálculos matemáticos de propósito general. Cuando necesita un valor entero con un rango de representaciones mayor que el tipo int, hay otros tipos de enteros disponibles para este propósito.

Entonces, si el valor necesita almacenarse sin un signo, entonces puede seleccionar tipo único, para valores con signo grandes - tipo largo y para valores grandes sin signo, escriba ulong. A modo de ejemplo, a continuación se muestra un programa que calcula la distancia de la Tierra al Sol en centímetros. Para almacenar un valor tan grande, utiliza una variable larga:

Usando el Sistema; usando System.Collections.Generic; usando System.Linq; usando System.Text; espacio de nombres ConsoleApplication1 ( clase Programa ( static void Main(string args) ( resultado largo; const long km = 149800000; // distancia en km. resultado = km * 1000 * 100; Console.WriteLine(resultado); Console.ReadLine(); ) ) )

A todas las variables enteras se les pueden asignar valores en notación decimal o hexadecimal. En el último caso, se requiere un prefijo 0x:

Largo x = 0x12ab;

Si existe alguna incertidumbre sobre si un valor entero es de tipo int, uint, long o ulong, entonces por defecto Se acepta int. Para especificar explícitamente qué otro tipo de entero debe tener un valor, se pueden agregar los siguientes caracteres a un número:

Uint ui = 1234U; largo l = 1234L; ulong ul = 1234UL;

U y L también se pueden escribir en minúsculas, aunque una L minúscula puede confundirse visualmente fácilmente con el número 1 (uno).

Tipos de coma flotante

Los tipos de coma flotante le permiten representar números con una parte fraccionaria. Hay dos tipos de datos de punto flotante en C#: flotar Y doble. Representan valores numéricos con precisión simple y doble, respectivamente. Por tanto, el ancho del tipo flotante es de 32 bits, lo que corresponde aproximadamente al rango de representación de números desde 5E-45 hasta 3,4E+38. Y el ancho del tipo doble es de 64 bits, lo que corresponde aproximadamente al rango de representación de números desde 5E-324 hasta 1,7E+308.

El tipo de datos flotante está destinado a valores de punto flotante más pequeños que requieren menos precisión. El tipo de datos doble es mayor que el flotante y ofrece un mayor grado de precisión (15 bits).

Si un valor no entero está codificado en el código fuente (por ejemplo, 12.3), entonces el compilador generalmente asume que se pretende un valor doble. Si es necesario especificar el valor como flotante, deberá agregarle el carácter F (of):

Flotador f = 12,3F;

Tipo de datos decimales

También se proporciona un tipo decimal para representar números de punto flotante de alta precisión. decimal, que está destinado a ser utilizado en cálculos financieros. Este tipo tiene un ancho de 128 bits para representar valores numéricos que van desde 1E-28 hasta 7,9E+28. Probablemente sepa que la aritmética normal de punto flotante es propensa a errores de redondeo decimal. Estos errores se eliminan utilizando el tipo decimal, que permite representar los números con 28 (y a veces 29) decimales. Debido a que este tipo de datos puede representar valores decimales sin errores de redondeo, es especialmente útil para cálculos relacionados con finanzas:

Usando el Sistema; usando System.Collections.Generic; usando System.Linq; usando System.Text; espacio de nombres ConsoleApplication1 ( clase Programa ( static void Main(string args) ( // *** Cálculo del costo de una inversión con *** // *** tasa de rendimiento fija*** decimal dinero, porcentaje; int i; años de bytes constantes = 15; dinero = 1000,0 m; por ciento = 0,045 m;

El resultado de este programa será:

Símbolos

En C#, los caracteres no se representan en código de 8 bits, como en muchos otros lenguajes de programación como C++, sino en código de 16 bits, llamado Unicódigo. El conjunto de caracteres de Unicode es tan amplio que cubre caracteres de casi todos los lenguajes naturales del mundo. Si bien muchos idiomas naturales, incluidos el inglés, el francés y el alemán, tienen alfabetos relativamente pequeños, algunos otros idiomas, como el chino, utilizan conjuntos de caracteres bastante grandes que no pueden representarse mediante un código de 8 bits. Para superar esta limitación, C# define tipo char, que representa valores de 16 bits sin signo que van de 0 a 65,535. Sin embargo, el conjunto de caracteres ASCII estándar de 8 bits es un subconjunto de Unicode que va de 0 a 127. Por lo tanto, los caracteres ASCII siguen siendo válidos en C#.

Una diferencia importante entre el lenguaje SI y otros lenguajes (PL1, FORTRAN, etc.) es la ausencia de un principio predeterminado, lo que lleva a la necesidad de declarar explícitamente todas las variables utilizadas en el programa junto con una indicación de sus tipos correspondientes. .

Las declaraciones de variables tienen el siguiente formato:

[especificador de clase de memoria] descriptor de especificador de tipo [=iniciador] [,descriptor [=iniciador] ]...

Un descriptor es un identificador de una variable simple o una construcción más compleja con corchetes, paréntesis o un asterisco (un conjunto de asteriscos).

Un especificador de tipo es una o más palabras clave que determinan el tipo de variable que se declara. El lenguaje SI tiene un conjunto estándar de tipos de datos, mediante el cual se pueden construir tipos de datos nuevos (únicos).

Iniciador: especifica el valor inicial o la lista de valores iniciales que se asignan a la variable cuando se declara.

Especificador de clase de memoria: determinado por una de las cuatro palabras clave SI: auto, extern, registro, estático e indica cómo se asignará la memoria para la variable declarada, por un lado, y, por otro, el alcance de esta variable. es decir, desde qué partes del programa se puede acceder.

1.2.1 Categorías de tipos de datos

Palabras clave para definir tipos de datos básicos

Tipos de enteros: Tipos flotantes: char float int doble corto largo doble largo con signo sin signo

Una variable de cualquier tipo puede declararse no modificable. Esto se logra agregando la palabra clave const al especificador de tipo. Los objetos con tipo const representan datos de solo lectura, es decir. A esta variable no se le puede asignar un nuevo valor. Tenga en cuenta que si no hay ningún especificador de tipo después de la palabra const, entonces el especificador de tipo int está implícito. Si la palabra clave const va antes de la declaración de tipos compuestos (matriz, estructura, mezcla, enumeración), esto lleva al hecho de que cada elemento tampoco debe ser modificable, es decir. solo se le puede asignar un valor una vez.

Const doble A=2,128E-2; constante B=286; (const int B=286 está implícito)

A continuación se analizarán ejemplos de declaración de datos compuestos.

1.2.2. tipo de datos entero

Para definir datos de tipo entero, se utilizan varias palabras clave que determinan el rango de valores y el tamaño del área de memoria asignada para las variables (Tabla 6).

Tabla 6

Tenga en cuenta que las palabras clave firmadas y sin firmar son opcionales. Indican cómo se interpreta el bit cero de la variable declarada, es decir, si se especifica la palabra clave sin signo, entonces el bit cero se interpreta como parte de un número; de lo contrario, el bit cero se interpreta como con signo. Si falta la palabra clave sin firmar, la variable entera se considera firmada. Si el especificador de tipo consta de un tipo de clave con o sin signo seguido de un identificador de variable, se tratará como una variable de tipo int. Por ejemplo:

Ent sin firmar n; int sin signo b; intc; (se da a entender int c firmado); d sin firmar; (implica unsigned int d); firmado f; (Se da a entender que el int f con signo).

Tenga en cuenta que el modificador de tipo char se utiliza para representar un carácter (a partir de una representación de matriz de caracteres) o para declarar cadenas literales. El valor de un objeto char es el código de 1 byte correspondiente al carácter que representa. Para representar caracteres del alfabeto ruso, el modificador de tipo de identificador de datos es unsigned char, ya que los códigos de letras rusas superan el valor de 127.

Se debe hacer la siguiente nota: el lenguaje SI no define la representación en memoria ni el rango de valores para identificadores con los modificadores de tipo int y unsigned int. El tamaño de la memoria para una variable con el modificador de tipo int con signo está determinado por la longitud de la palabra de la máquina, que tiene un tamaño diferente en diferentes máquinas. Entonces, en máquinas de 16 bits el tamaño de la palabra es de 2 bytes, en máquinas de 32 bits es de 4 bytes, es decir El tipo int es equivalente a los tipos short int o long int, dependiendo de la arquitectura de la PC utilizada. Así, un mismo programa puede funcionar correctamente en un ordenador y de forma incorrecta en otro. Para determinar la longitud de la memoria ocupada por una variable, puede utilizar el operador sizeof del lenguaje SI, que devuelve la longitud del modificador de tipo especificado.

Por ejemplo:

A = tamaño de (int); b = tamaño de (int largo); c = tamaño de (largo sin firmar); d = tamaño de (corto);

Tenga en cuenta también que las constantes octales y hexadecimales también pueden tener el modificador sin signo. Esto se logra especificando el prefijo u o U después de la constante; una constante sin este prefijo se considera firmada.

Por ejemplo:

0xA8C (int firmado); 01786l (firmado durante mucho tiempo); 0xF7u (int sin firmar);

1.2.3. Datos flotantes

Para las variables que representan un número de punto flotante, se utilizan los siguientes modificadores de tipo: flotante, doble, doble largo (en algunas implementaciones del lenguaje doble largo no hay SI).

Un valor con el modificador de tipo flotante ocupa 4 bytes. De ellos, se asigna 1 byte para el signo, 8 bits para el exponente sobrante y 23 bits para la mantisa. Tenga en cuenta que el bit más significativo de la mantisa es siempre 1, por lo que no se llena, por lo que el rango de valores para una variable de punto flotante es aproximadamente 3,14E-38 a 3,14E+38.

Un valor doble ocupa 8 bits de memoria. Su formato es similar al formato flotante. Los bits de memoria se distribuyen de la siguiente manera: 1 bit para el signo, 11 bits para el exponente y 52 bits para la mantisa. Teniendo en cuenta el bit alto omitido de la mantisa, el rango de valores es de 1,7E-308 a 1,7E+308.

Flotador f, a, b; doble x,y;

1.2.4. Señales

Un puntero es la dirección de memoria asignada para acomodar un identificador (el identificador puede ser el nombre de una variable, matriz, estructura o cadena literal). Si una variable se declara como un puntero, contiene una dirección de memoria donde se puede ubicar un valor escalar de cualquier tipo. Al declarar una variable de tipo puntero, debe especificar el tipo de objeto de datos cuya dirección contendrá la variable y el nombre del puntero precedido por un asterisco (o grupo de asteriscos). Formato de declaración de puntero:

especificador de tipo [modificador] * especificador.

El especificador de tipo especifica el tipo de objeto y puede ser cualquier tipo básico, tipo de estructura o mezcla (esto se discutirá más adelante). Al especificar la palabra clave void en lugar del especificador de tipo, puede diferir de forma única la especificación del tipo al que se refiere el puntero. Una variable declarada como puntero al tipo void se puede utilizar para hacer referencia a un objeto de cualquier tipo. Sin embargo, para poder realizar operaciones aritméticas y lógicas sobre punteros o sobre los objetos a los que apuntan, es necesario determinar explícitamente el tipo de objetos al realizar cada operación. Estas definiciones de tipos se pueden realizar mediante la operación de conversión de tipos.

Las palabras clave const, near, far, huge pueden usarse como modificadores al declarar un puntero. La palabra clave const indica que el puntero no se puede modificar en el programa. El tamaño de una variable declarada como puntero depende de la arquitectura de la computadora y del modelo de memoria utilizado para el cual se compilará el programa. Los punteros a diferentes tipos de datos no tienen por qué tener la misma longitud.

Para modificar el tamaño del puntero, puede utilizar las palabras clave cerca, lejos, enorme.

Int sin firmar * a; /* la variable a es un puntero al tipo unsigned int */ double * x; /* variable x indica tipo de datos de coma flotante de doble precisión */ char * fuffer ; /* declara un puntero llamado fuffer que apunta a una variable de tipo char */ double nomer; direcciones nulas *; direcciones = &nomer; (doble *)direcciones++; /* La variable dirección se declara como un puntero a un objeto de cualquier tipo. Por tanto, se le puede asignar la dirección de cualquier objeto (& es la operación de calcular la dirección). Sin embargo, como se señaló anteriormente, no se puede realizar ninguna operación aritmética en un puntero a menos que se determine explícitamente el tipo de datos al que apunta. Esto se puede hacer usando una operación de conversión (doble *) para convertir direcciones en un puntero para escribir doble y luego incrementar la dirección. */ constante * dr; /* La variable dr se declara como un puntero a una expresión constante, es decir El valor de un puntero puede cambiar durante la ejecución del programa, pero el valor al que apunta no. */ carácter sin firmar * const w = &obj. /* La variable w se declara como un puntero constante a datos de caracteres sin firmar. Esto significa que w apuntará a la misma ubicación de memoria durante todo el programa. El contenido de esta área puede cambiarse. */

1.2.5. Variables enumeradas

Una variable que puede tomar un valor de alguna lista de valores se llama variable enumerada o enumeración.

Una declaración de enumeración comienza con la palabra clave enum y tiene dos formatos de presentación.

Formato 1. enum [nombre-etiqueta-enum] (lista-enum) descriptor[,descriptor...];

Formato 2. enum enum-tag-name descriptor [,descriptor..];

Una declaración de enumeración especifica el tipo de variable de enumeración y define una lista de constantes con nombre denominada lista de enumeración. El valor de cada nombre de lista es un número entero.

Una variable de tipo enumeración puede tomar el valor de una de las constantes nombradas de la lista. Las constantes de lista con nombre son de tipo int. Por tanto, la memoria correspondiente a una variable de enumeración es la memoria necesaria para acomodar un valor int.

Las variables de tipo enum se pueden utilizar en expresiones de índice y como operandos en operaciones aritméticas y relacionales.

En el primer formato 1, los nombres y valores de enumeración se especifican en una lista de enumeración. El nombre de etiqueta de enumeración opcional es un identificador que nombra la etiqueta de enumeración definida por la lista de enumeración. El descriptor nombra una variable de enumeración. Se puede especificar más de una variable de tipo de enumeración en una declaración.

Una lista de enumeración contiene una o más construcciones de la forma:

identificador [= expresión constante]

Cada identificador nombra un elemento de la enumeración. Todos los identificadores de la lista de enumeración deben ser únicos. Si no hay una expresión constante, el primer identificador corresponde al valor 0, el siguiente identificador al valor 1, etc. El nombre de una constante de enumeración es equivalente a su valor.

Un identificador asociado con una expresión constante toma el valor especificado por esa expresión constante. La expresión constante debe ser de tipo int y puede ser positiva o negativa. Al siguiente identificador de la lista se le asigna el valor de la expresión constante más 1 si ese identificador no tiene su propia expresión constante. El uso de elementos de enumeración debe obedecer a las siguientes reglas:

1. La variable puede contener valores duplicados.

2. Los identificadores de una lista de enumeración deben ser distintos de todos los demás identificadores del mismo ámbito, incluidos los nombres de variables normales y los identificadores de otras listas de enumeración.

3. Los nombres de los tipos de enumeración deben ser distintos de otros nombres de tipos de enumeración, estructuras y mezclas en el mismo ámbito.

4. El valor puede seguir al último elemento de la lista de enumeración.

Semana de enumeración ( SUB = 0, /* 0 */ VOS = 0, /* 0 */ POND, /* 1 */ VTOR, /* 2 */ SRED, /* 3 */ HETV, /* 4 */ PJAT /* 5 */ ) rab_ned ;

En este ejemplo, se declara una etiqueta enumerable semana, con un conjunto de valores correspondiente, y se declara una variable rab_ned de tipo semana.

El segundo formato utiliza el nombre de la etiqueta enum para hacer referencia a un tipo de enumeración definido en otro lugar. El nombre de la etiqueta de enumeración debe hacer referencia a una etiqueta de enumeración ya definida dentro del alcance actual. Debido a que la etiqueta de enumeración se declara en otro lugar, la lista de enumeración no está representada en la declaración.

Al declarar un puntero a un tipo de datos de enumeración y declarar typedefs para tipos de enumeración, puede utilizar el nombre de una etiqueta de enumeración antes de definir esa etiqueta de enumeración. Sin embargo, la definición de enumeración debe preceder a cualquier uso del puntero de la declaración typedef al tipo. Una declaración sin una lista posterior de descriptores describe una etiqueta o, por así decirlo, un patrón de enumeración.

1.2.6. matrices

Los arrays son un grupo de elementos del mismo tipo (doble, flotante, int, etc.). De la declaración de la matriz, el compilador debe obtener información sobre el tipo de elementos de la matriz y su número. Una declaración de matriz tiene dos formatos:

descriptor de especificador de tipo [const - expresión];

descriptor de especificador de tipo;

El descriptor es el identificador de la matriz.

El especificador de tipo especifica el tipo de elementos de la matriz declarada. Los elementos de la matriz no pueden ser funciones o elementos vacíos.

La expresión constante entre corchetes especifica el número de elementos de la matriz. Al declarar una matriz, se puede omitir una expresión constante en los siguientes casos:

Cuando se declara, la matriz se inicializa,

La matriz se declara como un parámetro formal de la función,

SI define sólo matrices unidimensionales, pero dado que un elemento de una matriz puede ser una matriz, también se pueden definir matrices multidimensionales. Están formalizados mediante una lista de expresiones constantes que siguen al identificador de matriz, con cada expresión constante encerrada entre sus propios corchetes.

Cada expresión constante entre corchetes especifica el número de elementos a lo largo de esa dimensión de la matriz, de modo que una declaración de matriz bidimensional contiene dos expresiones constantes, una matriz tridimensional contiene tres, y así sucesivamente. Tenga en cuenta que en SI, el primer elemento de una matriz tiene un índice de 0.

Ent a; /* representado como una matriz a a a a a */ double b; /* vector de 10 elementos de tipo double */ int w = ( ( 2, 3, 4 ), ( 3, 4, 8 ), ( 1, 0, 9 ) );

En el último ejemplo, se declara la matriz w. Las listas entre llaves corresponden a cadenas de matriz; si no hay llaves, la inicialización no se realizará correctamente.

En el lenguaje SI, se pueden utilizar secciones de matriz, como en otros lenguajes de alto nivel (PL1, etc.), sin embargo, se imponen una serie de restricciones al uso de secciones. Las secciones se forman omitiendo uno o más pares de corchetes. Los pares de corchetes solo se pueden eliminar de derecha a izquierda y de forma estrictamente secuencial. Se utilizan secciones de matrices para organizar el proceso computacional en funciones SI desarrolladas por el usuario.

Si escribe s al llamar a una función, se pasará la cadena cero de la matriz s.

Al acceder a una matriz b, puede escribir, por ejemplo, b y se transferirá un vector de cuatro elementos, y al acceder a b se obtendrá una matriz bidimensional de tamaño 3 por 4. No puede escribir b, lo que implica que se creará un vector. ser transferido, porque esto no cumple con la restricción impuesta sobre el uso de secciones de matriz.

Un ejemplo de declaración de matriz de caracteres.

char str = "declaración de matriz de caracteres";

Tenga en cuenta que hay un elemento más en un carácter literal, ya que el último elemento es la secuencia de escape "\0".

1.2.7. Estructuras

Las estructuras son un objeto compuesto que incluye elementos de cualquier tipo, a excepción de funciones. A diferencia de una matriz, que es un objeto homogéneo, una estructura puede ser heterogénea. El tipo de estructura está determinado por una entrada del formulario:

estructura (lista de definiciones)

Se debe especificar al menos un componente en la estructura. La definición de estructuras es la siguiente:

descriptor de tipo de datos;

donde tipo de datos especifica el tipo de estructura de los objetos definidos en los descriptores. En su forma más simple, los identificadores son identificadores o matrices.

Estructura ( doble x,y; ) s1, s2, sm; estructura (int año; char polilla, día;) fecha1, fecha2;

Las variables s1, s2 se definen como estructuras, cada una de las cuales consta de dos componentes xey. La variable sm se define como una matriz de nueve estructuras. Cada una de las dos variables fecha1, fecha2 consta de tres componentes año, mes y día. >p>Existe otra forma de asociar un nombre a un tipo de estructura, se basa en el uso de una etiqueta de estructura. Una etiqueta de estructura es similar a una etiqueta de tipo enumeración. La etiqueta de estructura se define de la siguiente manera:

etiqueta de estructura (lista de descripciones;);

donde etiqueta es un identificador.

El siguiente ejemplo describe el identificador de estudiante como una etiqueta de estructura:

Estructura estudiante ( nombre char; int id, edad; char prp; );

La etiqueta de estructura se utiliza para declarar posteriormente estructuras de este tipo en el formulario:

etiqueta de lista de identificación de estructura;

estructura estudiante st1,st2;

El uso de etiquetas de estructura es necesario para describir estructuras recursivas. A continuación se analiza el uso de etiquetas de estructura recursivas.

Nodo de estructura ( int datos; nodo de estructura * siguiente; ) st1_node;

El nodo de etiqueta de estructura es efectivamente recursivo ya que se utiliza en su propia descripción, es decir en la formalización del siguiente puntero. Las estructuras no pueden ser directamente recursivas, es decir una estructura de nodo no puede contener un componente que sea una estructura de nodo, pero cualquier estructura puede tener un componente que sea un puntero a su tipo, como se hace en el ejemplo anterior.

Se accede a los componentes de la estructura especificando el nombre de la estructura y lo siguiente, separado por un punto, el nombre del componente seleccionado, por ejemplo:

St1.name="Ivánov"; st2.id=st1.id; st1_node.data=st1.age;

1.2.8. Combinaciones (mezclas)

Una unión es similar a una estructura, pero sólo uno de los elementos de la unión puede usarse (o en otras palabras responderse) en cualquier momento. El tipo de unión se puede especificar de la siguiente manera:

Unión ( elemento 1 descripción; ... elemento n descripción; );

La característica principal de una unión es que se asigna la misma área de memoria para cada uno de los elementos declarados, es decir se superponen. Aunque se puede acceder a esta región de memoria utilizando cualquiera de los elementos, se debe seleccionar el elemento destinado a tal fin para que el resultado obtenido no carezca de significado.

Se accede a los miembros de un sindicato del mismo modo que a las estructuras. La etiqueta de unión se puede formalizar exactamente de la misma manera que la etiqueta de estructura.

La asociación se utiliza para los siguientes fines:

Inicializar un objeto de memoria en uso si en un momento dado sólo uno de muchos objetos está activo;

Interpretar la representación subyacente de un objeto de un tipo como si a ese objeto se le asignara un tipo diferente.

La memoria que corresponde a una variable de tipo unión está determinada por la cantidad requerida para acomodar el elemento más largo de la unión. Cuando se utiliza un elemento más corto, la variable de tipo unión puede contener memoria no utilizada. Todos los elementos de una unión se almacenan en la misma área de memoria, comenzando en la misma dirección.

Unión (char fio; char direcciones; int vozrast; int telefon; ) informar; unión (int ax; char al;) ua;

Cuando se utiliza un objeto infor de tipo unión, puede procesar solo el elemento que recibió el valor, es decir Después de asignar un valor al elemento inform.fio, no tiene sentido acceder a otros elementos. La concatenación ua permite el acceso separado a los bytes ua.al bajo y ua.al alto del número de dos bytes ua.ax.

1.2.9. campos de bits

Un elemento de la estructura puede ser un campo de bits que proporciona acceso a bits individuales de memoria. Los campos de bits no se pueden declarar fuera de las estructuras. Tampoco puede organizar matrices de campos de bits y no puede aplicar la operación de determinación de dirección a los campos. En general, el tipo de estructura con campo de bits se especifica de la siguiente manera:

Estructura (identificador sin firmar 1: longitud del campo 1; identificador sin firmar 2: longitud del campo 2;)

longitud: los campos se especifican mediante una expresión entera o una constante. Esta constante especifica el número de bits asignados al campo correspondiente. Un campo de longitud cero indica alineación con el límite de la siguiente palabra.

Estructura (a1 sin firmar: 1; a2 sin firmar: 2; a3 sin firmar: 5; a4 sin firmar: 2;) prim;

Las estructuras de campos de bits también pueden contener componentes firmados. Dichos componentes se colocan automáticamente en límites de palabras apropiados y es posible que algunos bits de palabras queden sin utilizar.

1.2.10. Variables con estructura mutable.

Muy a menudo, algunos objetos de programa pertenecen a la misma clase y difieren sólo en algunos detalles. Consideremos, por ejemplo, la representación de formas geométricas. La información general sobre formas puede incluir elementos como área y perímetro. Sin embargo, la información de las dimensiones geométricas correspondientes puede diferir según su forma.

Consideremos un ejemplo en el que se representa información sobre formas geométricas basándose en el uso combinado de estructura y unión.

Figura de estructura ( área doble, perímetro; /* componentes comunes */ tipo int; /* atributo de componente */ unión /* enumeración de componentes */ ( radio doble; /* círculo */ doble a; /* rectángulo */ doble b ; /* triángulo */ ) geom_fig ) fig1, fig2;

En general, cada objeto figura constará de tres componentes: área, perímetro y tipo. El componente de tipo se denomina etiqueta de componente activo porque se utiliza para indicar qué componente de la unión geom_fig está activo actualmente. Esta estructura se denomina estructura variable porque sus componentes cambian según el valor de la etiqueta del componente activo (el valor de tipo).

Tenga en cuenta que en lugar de un componente de tipo int, sería recomendable utilizar un tipo enumerado. Por ejemplo, así

Enum figura_ajedrez (CÍRCULO, CAJA, TRIÁNGULO);

Las constantes CIRCLE, BOX, TRIANGLE recibirán valores iguales a 0, 1, 2, respectivamente. La variable de tipo se puede declarar como de tipo enumerado:

enumeración figura_ajedrez tipo;

En este caso, el compilador SI advertirá al programador sobre asignaciones potencialmente erróneas, como

figura.tipo = 40;

En general, una variable de estructura constará de tres partes: un conjunto de componentes comunes, una etiqueta para el componente activo y una parte con componentes cambiantes. La forma general de una estructura variable es la siguiente:

Estructura (componentes comunes; etiqueta de componente activo; unión (descripción del componente 1; descripción del componente 2; ::: descripción del componente n; ) identificador de unión; ) identificador de estructura;

Ejemplo de definición de una variable de estructura denominada helth_record

Struct ( /* información general */ char nombre ; /* nombre */ int edad; /* edad */ char sexo; /* género */ /* etiqueta de componente activo */ /* (estado civil) */ enum merital_status ins ; /* parte variable */ union ( /* soltero */ /* sin componente */ struct ( /* casado */ char nombre_conyugue; int no_hijos; ) información_matrimonio; /* divorciado */ char fecha_divorciada; ) información_marital ) registro_salud; enum estado_marital ( SOLTERO, /* soltero */ MARRIGO, /* casado */ DIVORIDO /* divorciado */ );

Puede acceder a los componentes de la estructura mediante enlaces:

Helth_record.neme, helth_record.ins, helth_record.marriage_info.marriage_date.

1.2.11. Definición de objetos y tipos

Como se mencionó anteriormente, se deben declarar todas las variables utilizadas en los programas SI. El tipo de variable que se declara depende de qué palabra clave se utiliza como especificador de tipo y de si el especificador es un identificador simple o una combinación de un identificador con un puntero (asterisco), una matriz (corchetes) o un modificador de función (paréntesis).

Al declarar una variable simple, estructura, mezcla o unión, o enumeración, el descriptor es un identificador simple. Para declarar un puntero, matriz o función, el identificador se modifica en consecuencia: un asterisco a la izquierda, un cuadrado o paréntesis a la derecha.

Observemos una característica importante del lenguaje SI: al declarar, se puede usar más de un modificador simultáneamente, lo que permite crear muchos descriptores de tipos complejos diferentes.

Sin embargo, debemos recordar que algunas combinaciones de modificadores son inaceptables:

Los elementos de una matriz no pueden ser funciones.

Las funciones no pueden devolver matrices o funciones.

Al inicializar descriptores complejos, los corchetes y paréntesis (a la derecha del identificador) tienen prioridad sobre el asterisco (a la izquierda del identificador). Los cuadrados o paréntesis tienen la misma precedencia y se expanden de izquierda a derecha. El especificador de tipo se considera en el último paso, cuando el descriptor ya ha sido interpretado completamente. Puede utilizar paréntesis para cambiar el orden de interpretación según sea necesario.

Para interpretar descripciones complejas, se propone una regla simple que suena como "de adentro hacia afuera" y consta de cuatro pasos.

1. Comience con el identificador y mire hacia la derecha para ver si hay cuadrados o paréntesis.

2. Si es así, entonces interpreta esta parte del descriptor y luego mira hacia la izquierda en busca de un asterisco.

3. Si en algún momento se encuentra un paréntesis de cierre a la derecha, primero se deben aplicar todas estas reglas dentro del paréntesis y luego continúa la interpretación.

4. Interprete el especificador de tipo.

Int * (* comp ) (); 6 5 3 1 2 4

Este ejemplo declara la variable comp (1) como una matriz de diez (2) punteros (3) a funciones (4) que devuelven punteros (5) a valores enteros (6).

Char * (* (*var) ()); 7 6 4 2 1 3 5

La variable var (1) se declara como un puntero (2) a una función (3) que devuelve un puntero (4) a una matriz (5) de 10 elementos, que son punteros (6) a valores char.

Además de declarar variables de varios tipos, es posible declarar tipos. Esto se puede hacer de dos formas. La primera forma es especificar un nombre de etiqueta al declarar una estructura, unión o enumeración y luego usar ese nombre en declaraciones de variables y funciones como referencia a esa etiqueta. El segundo es utilizar la palabra clave typedef para declarar un tipo.

Cuando se declara con la palabra clave typedef, el identificador en lugar del objeto que se describe es el nombre del tipo de datos que se está considerando, y este tipo se puede usar para declarar variables.

Tenga en cuenta que se puede declarar cualquier tipo utilizando la palabra clave typedef, incluidos los tipos de puntero, función o matriz. Se puede declarar un nombre con la palabra clave typedef para tipos de puntero, estructura y unión antes de que se definan esos tipos, pero dentro del alcance del declarante.

Typedef doble(*MATEMÁTICAS)(); /* MATH - nuevo nombre de tipo que representa un puntero a una función que devuelve valores dobles */ MATH cos; /* puntero cos a una función que devuelve valores de tipo double */ /* Se puede hacer una declaración equivalente */ double (* cos)(); typedef char FIO /* FIO - matriz de cuarenta caracteres */ persona FIO; /* La variable persona es una matriz de cuarenta caracteres */ /* Esto es equivalente a una declaración */ char person;

Al declarar variables y tipos, aquí se utilizaron nombres de tipos (MATH FIO). Además, los nombres de tipos se pueden utilizar en otros tres casos: en la lista de parámetros formales, en declaraciones de funciones, en operaciones de conversión de tipos y en la operación sizeof (operación de conversión de tipos).

Los nombres de tipo para tipos básicos, de enumeración, de estructura y de mezcla son los especificadores de tipo para esos tipos. Los nombres de tipo para los tipos de función y puntero de matriz se especifican mediante descriptores abstractos de la siguiente manera:

especificador-de-tipo-descriptor-abstracto;

Un controlador abstracto es un controlador no identificador que consta de uno o más modificadores de puntero, matriz o función. El modificador de puntero (*) siempre se coloca antes del identificador en el descriptor, y los modificadores de matriz y función () se colocan después. Por tanto, para interpretar correctamente un descriptor abstracto, se debe comenzar la interpretación con el identificador implícito.

Los descriptores abstractos pueden ser complejos. Los paréntesis en descriptores abstractos complejos especifican el orden de interpretación de manera similar a la interpretación de descriptores complejos en declaraciones.

1.2.12. Inicialización de datos

Cuando se declara una variable, se le puede asignar un valor inicial agregando un iniciador a un declarador. El iniciador comienza con el signo "=" y tiene las siguientes formas.

Formato 1: = iniciador;

Formato 2: = (lista - iniciadores);

El formato 1 se utiliza al inicializar variables de tipos básicos y punteros, y el formato 2 se utiliza al inicializar objetos compuestos.

La variable tol se inicializa con el carácter "N".

const long megabute = (1024 * 1024);

La variable megabute no modificable se inicializa con una expresión constante después de la cual no se puede cambiar.

estático int b = (1,2,3,4);

Se inicializa una matriz bidimensional de b valores enteros; a los elementos de la matriz se les asignan valores de la lista. La misma inicialización se puede hacer así:

estático int b = ((1,2), (3,4));

Al inicializar una matriz, puede omitir una o más dimensiones

int estático b)


Arriba