
Die Programmiersprache C ist unglaublich beliebt, und es ist leicht zu verstehen, warum. Die Programmierung in C ist effizient und gibt dem Programmierer viel Kontrolle. Viele andere Programmiersprachen wie C++, Java und Python wurden mit C entwickelt.
Die Chancen steigen jeden Tag, dass Sie als Programmierer C nicht ausschließlich für Ihre Arbeit verwenden. Das Erlernen von C ist jedoch sehr vorteilhaft, auch wenn Sie es nicht regelmäßig verwenden. Hier ist der Grund:
Sie können Code für Software lesen und schreiben, die auf vielen verschiedenen Arten von Computerplattformen verwendet werden kann, darunter alles von kleinen Mikrocontrollern bis hin zu Desktop-, Laptop- und mobilen Betriebssystemen.
Sie werden besser verstehen, was Hochsprachen hinter den Kulissen tun, wie z. B. Speicherverwaltung und Garbage Collection. Dieses Verständnis kann Ihnen helfen, Programme zu schreiben, die effizienter arbeiten.
Wenn Sie ein Spezialist für Informationstechnologie (IT) sind, könnten Sie auch davon profitieren, C zu lernen. IT-Experten schreiben, pflegen und führen im Rahmen ihrer Arbeit häufig Skripte aus. Ein Skript ist eine Liste von Anweisungen, denen das Betriebssystem eines Computers folgen soll. Um bestimmte Skripte auszuführen, richtet der Computer eine kontrollierte Ausführungsumgebung namens Shell ein . Da die meisten Betriebssysteme Shells ausführen, die auf C basieren, ist die C-Shell eine beliebte Scripting-Adaption von C, die von IT-Profis verwendet wird.
Dieser Artikel behandelt die Geschichte hinter C, untersucht, warum C so wichtig ist, zeigt Beispiele für grundlegenden C-Code und untersucht einige wichtige Merkmale von C, darunter Datentypen, Operationen, Funktionen, Zeiger und Speicherverwaltung. Obwohl dieser Artikel keine Anleitung zum Programmieren in C ist, behandelt er, was die C-Programmierung einzigartig macht, und zwar auf eine Weise, die über die ersten paar Kapitel eines durchschnittlichen C-Programmierhandbuchs hinausgeht.
Schauen wir uns zunächst an, woher die Programmiersprache C stammt, wie sie sich entwickelt hat und welche Rolle sie heute in der Softwareentwicklung spielt.
- Was ist C?
- Bearbeiten und Kompilieren von C-Code
- Das einfachste C-Programm
- Allgemeine Programmierkonzepte in C
- Funktionen in C
- Funktionsprototypen
- Datentypen und Operationen in C
- Fangen Sie nicht bei Null an, verwenden Sie Bibliotheken
- Einige Hinweise zu Zeigern in C
- Richtige Verwendung von Zeigern in C
- Die Bedeutung der Speicherverwaltung in C
Was ist C?
Die einfachste Art, C zu definieren, besteht darin, es eine Computerprogrammiersprache zu nennen, was bedeutet, dass Sie damit Software schreiben können, die ein Computer ausführen kann. Das Ergebnis könnte eine große Computeranwendung wie Ihr Webbrowser oder ein winziger Satz von Anweisungen sein, die in einen Mikroprozessor oder eine andere Computerkomponente eingebettet sind.
Die Sprache C wurde in den frühen 1970er Jahren in den Bell Laboratories entwickelt und hauptsächlich auf die Arbeit von Ken Thompson und Dennis Ritchie zurückgeführt. Programmierer benötigten benutzerfreundlichere Anweisungen für das UNIX-Betriebssystem, das zu dieser Zeit Programme erforderte, die in Assemblersprache geschrieben waren. Assembler-Programme, die direkt mit der Hardware eines Computers kommunizieren, sind langwierig und schwer zu debuggen, und sie erforderten mühsame, zeitaufwändige Arbeit, um neue Funktionen hinzuzufügen [Quelle: King].
Thompsons erster Versuch einer Hochsprache hieß B, eine Hommage an die Systemprogrammiersprache BCPL, auf der sie basierte. Als Bell Labs ein UNIX-Systemmodell PDP-11 der Digital Equipment Corporation (DEC) erwarb, überarbeitete Thompson B, um den Anforderungen der neueren, besseren Systemhardware besser gerecht zu werden. Damit war der Nachfolger von B, C, geboren. Bis 1973 war C stabil genug, dass UNIX selbst mit dieser innovativen neuen Sprache auf höherer Ebene neu geschrieben werden konnte [Quelle: King].
Bevor C außerhalb von Bell Labs effektiv eingesetzt werden konnte, brauchten andere Programmierer ein Dokument, das erklärt, wie man es benutzt. 1978 wurde das Buch „The C Programming Language“ von Brian Kernighan und Dennis Ritchie, unter C-Enthusiasten als K&R oder „White Book“ bekannt, zur maßgeblichen Quelle für die C-Programmierung. Während ich dies schreibe, ist die zweite Ausgabe von K&R, die ursprünglich 1988 veröffentlicht wurde, immer noch weit verbreitet. Die ursprüngliche Vorstandardversion von C heißt K&R C und basiert auf diesem Buch.
Um sicherzustellen, dass die Menschen im Laufe der Zeit nicht ihre eigenen Dialekte entwickelten, arbeiteten C-Entwickler in den 1980er Jahren daran, Standards für die Sprache zu erstellen. Der US-Standard für C, American National Standards Institute (ANSI) Standard X3.159-1989, wurde 1989 offiziell. Der International Organization for Standardization (ISO) Standard, ISO/IEC 9899:1990, folgte 1990. Die Versionen von C nachdem K&R auf diese Standards und ihre späteren Überarbeitungen (C89, C90 und C99) Bezug genommen hat. Möglicherweise wird C89 auch als „ANSI C“, „ANSI/ISO C“ oder „ISO C“ bezeichnet.
C und seine Verwendung in UNIX waren nur ein Teil des Booms in der Entwicklung von Betriebssystemen in den 1980er Jahren. Trotz all seiner Verbesserungen gegenüber seinen Vorgängern war C jedoch immer noch nicht einfach für die Entwicklung größerer Softwareanwendungen zu verwenden. Als Computer leistungsfähiger wurden, stieg die Nachfrage nach einer einfacheren Programmiererfahrung. Diese Nachfrage veranlasste Programmierer, ihre eigenen Compiler und damit ihre eigenen neuen Programmiersprachen mit C zu entwickeln. Diese neuen Sprachen könnten die Codierung komplexer Aufgaben mit vielen beweglichen Teilen vereinfachen. Beispielsweise vereinfachten Sprachen wie C++ und Java, die beide aus C entwickelt wurden, die objektorientierte Programmierung, einen Programmieransatz, der die Fähigkeit eines Programmierers optimiert, Code wiederzuverwenden.
Nachdem Sie nun ein wenig Hintergrund kennen, wollen wir uns die Mechanik von C selbst ansehen.
Bearbeiten und Kompilieren von C-Code
C wird als kompilierte Sprache bezeichnet, was bedeutet, dass Sie einen Compiler verwenden müssen, um den Code in eine ausführbare Datei umzuwandeln, bevor Sie ihn ausführen können. Der Code wird in eine oder mehrere Textdateien geschrieben, die Sie in jedem Texteditor wie Notepad in Windows, TextEdit auf einem Mac und gedit in Linux öffnen, lesen und bearbeiten können. Eine ausführbare Datei ist etwas, das der Computer ausführen (ausführen) kann. Der Compiler überprüft den Code auf Fehler und erstellt, wenn er fehlerfrei zu sein scheint, eine ausführbare Datei.
Bevor wir uns ansehen, was in den C-Code einfließt, wollen wir sicherstellen, dass wir einen C-Compiler finden und verwenden können. Wenn Sie Mac OS X und die meisten Linux-Distributionen (z. B. Ubuntu) verwenden, können Sie Ihrem Computer einen C-Compiler hinzufügen, wenn Sie die Entwicklungstools-Software für dieses bestimmte Betriebssystem installieren. Diese kostenlosen C-Compiler sind Befehlszeilentools, was bedeutet, dass Sie sie normalerweise von einer Eingabeaufforderung in einem Terminalfenster ausführen. Der Befehl zum Ausführen eines dieser C-Compiler lautet „cc“ oder „gcc“ plus einige Befehlszeilenoptionen und -argumente, die andere Wörter sind, die nach dem Befehl eingegeben werden, bevor Sie die Eingabetaste drücken.
Wenn Sie Microsoft Windows verwenden oder lieber eine grafische Benutzeroberfläche als eine Befehlszeile verwenden möchten, können Sie eine integrierte Entwicklungsumgebung (IDE) für die C-Programmierung installieren. Eine IDE ist eine einzige Schnittstelle, auf der Sie Ihren Code schreiben, kompilieren, testen und Fehler schnell finden und beheben können. Für Windows können Sie Microsoft Visual C++-Software erwerben, eine IDE für die C- und C++-Programmierung. Eine weitere beliebte IDE ist Eclipse, eine kostenlose Java-basierte IDE, die unter Windows, Mac und Linux läuft und über Erweiterungen zum Kompilieren von C und vielen anderen Programmiersprachen verfügt.
Für C ist, wie für andere Computerprogrammiersprachen, die Version des verwendeten Compilers sehr wichtig. Sie möchten immer eine Version des C-Compilers verwenden, die genauso neu oder neuer ist als die Version der C-Sprache, die Sie in Ihrem Programm verwenden. Wenn Sie eine IDE verwenden, stellen Sie sicher, dass Sie Ihre Einstellungen anpassen, um sicherzustellen, dass die IDE Ihre Ziel-C-Version für das Programm verwendet, an dem Sie arbeiten. Wenn Sie sich an einer Befehlszeile befinden, können Sie ein Befehlszeilenargument hinzufügen, um die Version wie im folgenden Befehl zu ändern:
gcc –std c99 –o meinprogramm.exe meinprogramm.c
Im obigen Befehl ist „gcc“ der Aufruf zum Ausführen des Compilers und alles andere ist eine Befehlszeilenoption oder ein Argument. Die Option „-std“ wurde hinzugefügt, gefolgt von „c99“, um den Compiler anzuweisen, die C99-Standardversion von C während seiner Kompilierung zu verwenden. Die Option „-o“ wurde hinzugefügt, gefolgt von „myprogram.exe“, um anzufordern, dass die ausführbare Datei, die Ausgabedatei des Compilers, myprogram.exe heißt. Ohne "-o" wird die ausführbare Datei stattdessen automatisch a.out genannt. Das letzte Argument "myprogram.c" gibt die Textdatei mit dem zu kompilierenden C-Code an. Kurz gesagt, dieser Befehl sagt: "Hey, gcc, kompiliere myprogram.c unter Verwendung des C99-Programmierstandards und lege die Ergebnisse in eine Datei namens myprogram.exe."
Wenn Ihr Compiler installiert ist, können Sie in C programmieren. Beginnen wir damit, einen Blick auf die Grundstruktur eines der einfachsten C-Programme zu werfen, die Sie schreiben können.
Das einfachste C-Programm
Schauen wir uns ein einfaches C-Programm an und verwenden es, um die Grundlagen von C und den C-Kompilierungsprozess zu verstehen. Wenn Sie Ihren eigenen Computer haben, auf dem wie zuvor beschrieben ein C-Compiler installiert ist, können Sie eine Textdatei mit dem Namen sample.c erstellen und sie verwenden, um mitzumachen, während wir dieses Beispiel schrittweise durchgehen. Beachten Sie, dass Sie beim Kompilieren wahrscheinlich eine Art Fehler erhalten, wenn Sie das .c im Dateinamen weglassen oder wenn Ihr Editor .txt an den Namen anhängt.
Hier ist unser Beispielprogramm:
/* Beispielprogramm */
#enthalten
int Haupt()
{
printf("Dies ist die Ausgabe meines ersten Programms!\n");
0 zurückgeben;
}
Wenn dieses Programm kompiliert und ausgeführt wird, weist es den Computer an, die Zeile "Dies ist die Ausgabe meines ersten Programms!" und dann aufhören. Viel einfacher geht es nicht! Schauen wir uns nun an, was jede Zeile tut:
Zeile 1 -- Dies ist eine Möglichkeit, Kommentare in C zwischen /* und */ in einer oder mehreren Zeilen zu schreiben.
Zeile 2 – Der #include-Befehl weist den Compiler an, andere Quellen nach vorhandenem C-Code zu durchsuchen, insbesondere Bibliotheken, bei denen es sich um Dateien handelt, die allgemeine wiederverwendbare Anweisungen enthalten. Das verweist auf eine Standard-C-Bibliothek mit Funktionen zum Abrufen von Eingaben von einem Benutzer und zum Schreiben von Ausgaben auf dem Bildschirm. Bibliotheken werden wir uns später genauer ansehen.
Zeile 3 -- Diese Zeile ist die erste Zeile einer Funktionsdefinition. Jedes C-Programm hat mindestens eine Funktion oder einen Codeblock, der etwas darstellt, was der Computer tun soll, wenn das Programm läuft. Die Funktion führt ihre Aufgabe aus und erzeugt dann ein Nebenprodukt, das als Rückgabewert bezeichnet wird und von anderen Funktionen verwendet werden kann. Das Programm hat mindestens eine Funktion namens main wie die hier gezeigte mit einem Rückgabewert vom Datentyp int, was ganzzahlig bedeutet. Wenn wir uns die Funktionen später genauer ansehen, werden Sie sehen, was die leeren Klammern bedeuten.
Zeilen 4 und 7 -- Die Anweisungen innerhalb einer Funktion sind in geschweiften Klammern eingeschlossen. Einige Programmierer beginnen und beenden einen in geschweiften Klammern eingeschlossenen Block in separaten Zeilen, wie hier gezeigt. Andere setzen die offene Klammer ({) am Ende der ersten Zeile der Funktionsdefinition. Obwohl Codezeilen im Programm nicht in separaten Zeilen eingegeben werden müssen, schreiben Programmierer normalerweise jede Anweisung in eine separate Zeile, die mit Leerzeichen eingerückt ist, um den Code später leichter lesbar und editierbar zu machen.
Zeile 5 – Dies ist ein Funktionsaufruf einer Funktion namens printf. Diese Funktion ist in der stdio.h-Bibliothek codiert, die ab Zeile 1 enthalten ist, sodass Sie sie nicht selbst schreiben müssen. Dieser Aufruf von printf teilt ihm mit, was auf dem Bildschirm ausgegeben werden soll. Das \n am Ende innerhalb der Anführungszeichen wird jedoch nicht gedruckt; Es ist eine Escape-Sequenz, die printf anweist, den Cursor zur nächsten Zeile auf dem Bildschirm zu bewegen. Außerdem muss, wie Sie sehen, jede Zeile in der Funktion mit einem Semikolon enden.
Zeile 6 – Jede Funktion, die einen Wert zurückgibt, muss eine return-Anweisung wie diese enthalten. In C muss die Hauptfunktion immer einen ganzzahligen Rückgabetyp haben, auch wenn sie nicht innerhalb des Programms verwendet wird. Beachten Sie jedoch, dass Sie beim Ausführen eines C-Programms im Wesentlichen dessen Hauptfunktion ausführen. Wenn Sie also das Programm testen, können Sie den Computer anweisen, den Rückgabewert von der Ausführung des Programms anzuzeigen. Ein Rückgabewert von 0 wird bevorzugt, da Programmierer normalerweise beim Testen nach diesem Wert suchen, um zu bestätigen, dass das Programm erfolgreich ausgeführt wurde.
Wenn Sie bereit sind, Ihr Programm zu testen, speichern Sie die Datei, kompilieren und führen Sie das Programm aus. Wenn Sie den gcc-Compiler in einer Befehlszeile verwenden und sich das Programm in einer Datei namens sample.c befindet, können Sie es mit dem folgenden Befehl kompilieren:
gcc -o sample.exe sample.c
Wenn der Code keine Fehler enthält, sollte nach Ausführung dieses Befehls eine Datei namens sample.exe im selben Verzeichnis wie sample.c vorhanden sein. Der häufigste Fehler ist ein Syntaxfehler, was bedeutet, dass Sie sich vertippt haben, z. B. ein Semikolon am Ende einer Zeile weggelassen oder Anführungszeichen oder Klammern nicht geschlossen haben. Wenn Sie Änderungen vornehmen müssen, öffnen Sie die Datei in Ihrem Texteditor, korrigieren Sie sie, speichern Sie Ihre Änderungen und versuchen Sie Ihren Kompilierungsbefehl erneut.
Geben Sie den folgenden Befehl ein, um das Programm sample.exe auszuführen. Beachten Sie das ./, das den Computer zwingt, im aktuellen Verzeichnis nach der ausführbaren Datei zu suchen:
./sample.exe
Das sind die Grundlagen des Codierens und Kompilierens für C, obwohl Sie noch viel mehr über das Kompilieren von anderen C-Programmierressourcen lernen können. Lassen Sie uns nun die Schachtel öffnen und sehen, welche Teile C zum Erstellen von Programmen hat.
Allgemeine Programmierkonzepte in C
Werfen wir einen Blick darauf, wie Sie einige der gängigen Programmierkonzepte in Ihrem C-Code in die Praxis umsetzen können. Im Folgenden finden Sie eine kurze Zusammenfassung dieser Konzepte:
Funktionen -- Wie bereits erwähnt, ist eine Funktion ein Codeblock, der etwas darstellt, was der Computer tun soll, wenn das Programm läuft. Einige Sprachen nennen diese Strukturen Methoden, obwohl C-Programmierer diesen Begriff normalerweise nicht verwenden. Ihr Programm kann mehrere Funktionen definieren und diese Funktionen von anderen Funktionen aufrufen. Später werden wir uns die Struktur von Funktionen in C genauer ansehen.
Variablen -- Wenn Sie ein Programm ausführen, benötigen Sie manchmal die Flexibilität, das Programm auszuführen, ohne die Werte im Voraus zu kennen. Wie andere Programmiersprachen erlaubt Ihnen C, Variablen zu verwenden, wenn Sie diese Flexibilität benötigen. Wie Variablen in der Algebra ist eine Variable in der Computerprogrammierung ein Platzhalter, der für einen Wert steht, den Sie nicht kennen oder noch nicht gefunden haben.
Datentypen – Um Daten im Speicher zu speichern, während Ihr Programm läuft, und um zu wissen, welche Operationen Sie mit diesen Daten ausführen können, definiert eine Programmiersprache wie C bestimmte Datentypen, die sie erkennt. Jeder Datentyp in C hat eine bestimmte Größe, gemessen in binären Bits oder Bytes, und einen bestimmten Satz von Regeln darüber, was seine Bits darstellen. Als nächstes werden wir sehen, wie wichtig es ist, den richtigen Datentyp für die Aufgabe auszuwählen, wenn Sie C verwenden.
Operationen -- In C können Sie arithmetische Operationen (z. B. Addition) mit Zahlen und Zeichenfolgenoperationen (z. B. Verkettung) mit Zeichenfolgen ausführen. C verfügt auch über integrierte Operationen, die speziell für Dinge entwickelt wurden, die Sie möglicherweise mit Ihren Daten tun möchten. Wenn wir uns Datentypen in C ansehen, werfen wir auch einen kurzen Blick auf die Operationen.
Schleifen -- Eines der grundlegendsten Dinge, die ein Programmierer tun möchte, ist, eine Aktion einige Male zu wiederholen, basierend auf bestimmten Bedingungen, die auftreten, während das Programm läuft. Ein Codeblock, der sich basierend auf gegebenen Bedingungen wiederholen soll, wird als Schleife bezeichnet, und die C-Sprache stellt diese üblichen Schleifenstrukturen bereit: while, do/while, for, Continue/break und goto. C enthält auch die üblichen if/then/else-Bedingungen und switch/case-Anweisungen.
Datenstrukturen -- Wenn Ihr Programm viele Daten verarbeiten muss und Sie diese Daten sortieren oder durchsuchen müssen, werden Sie wahrscheinlich eine Art Datenstruktur verwenden. Eine Datenstruktur ist eine strukturierte Art, mehrere Daten des gleichen Datentyps darzustellen. Die gebräuchlichste Datenstruktur ist ein Array, das nur eine indizierte Liste einer bestimmten Größe ist. C verfügt über Bibliotheken, um einige gängige Datenstrukturen zu handhaben, obwohl Sie jederzeit Funktionen schreiben und auch Ihre eigenen Strukturen einrichten können.
Präprozessoroperationen -- Manchmal möchten Sie dem Compiler einige Anweisungen geben, was mit Ihrem Code zu tun ist, bevor Sie ihn in die ausführbare Datei kompilieren. Diese Operationen umfassen das Ersetzen konstanter Werte und das Einschließen von Code aus C-Bibliotheken (die Sie zuvor im Beispielcode gesehen haben).
C verlangt von Programmierern auch, einige Konzepte zu handhaben, die viele Programmiersprachen vereinfacht oder automatisiert haben. Dazu gehören Zeiger, Speicherverwaltung und Garbage Collection. Spätere Seiten behandeln die wichtigen Dinge, die Sie über diese Konzepte beim Programmieren in C wissen sollten.
Dieser schnelle Überblick über Konzepte mag überwältigend erscheinen, wenn Sie nicht bereits Programmierer sind. Bevor Sie zu einem umfangreichen C-Programmierleitfaden übergehen, werfen wir einen benutzerfreundlichen Blick auf die Kernkonzepte der oben aufgeführten, beginnend mit den Funktionen.
Funktionen in C
Most computer programming languages allow you to create functions of some sort. Functions let you chop up a long program into named sections so that you can reuse those sections throughout the program. Programmers for some languages, especially those using object-oriented programming techniques, use the term method instead of function.
Functions accept parameters and return a result. The block of code that comprises a function is its function definition. The following is the basic structure of a function definition:
{
return
}
At a minimum, a C program has one function named main. The compiler will look for a main function as the starting point for the program, even if the main function calls other functions within it. The following is the main we saw in the simple C program we looked at before. It has a return type of integer, takes no parameters, and has two statements (instructions within the function), one of which is its return statement:
int main()
{
printf("This is output from my first program!\n");
return 0;
}
Functions other than main have a definition and one or more function calls. A function call is a statement or part of a statement within another function. The function call names the function it's calling followed by parentheses. If the function has parameters, the function call must include corresponding values to match those parameters. This additional part of the function call is called passing parameters to the function.
But what are parameters? A parameter for a function is a piece of data of a certain data type that the function requires to do its work. Functions in C can accept an unlimited number of parameters, sometimes called arguments. Each parameter added to a function definition must specify two things: its data type and its variable name within the function block. Multiple parameters are be separated by a comma. In the following function, there are two parameters, both integers:
int doubleAndAdd(int a, int b)
{
return ((2*a)+(2*b));
}
Next, let's continue our look at functions by zooming out to look at how they fit within a larger C program.
Function Prototypes
In C, you can add a function definition anywhere within the program (except within another function). The only condition is that you must tell the compiler in advance that the function exists somewhere later in the code. You'll do this with a function prototype at the beginning of the program. The prototype is a statement that looks similar to the first line of the definition. In C, you don't have to give the names of the parameters in the prototype, only the data types. The following is what the function prototype would look like for the doubleAndAdd function:
int doubleAndAdd(int, int);
Imagine function prototypes as the packing list for your program. The compiler will unpack and assemble your program just as you might unpack and assemble a new bookshelf. The packing list helps you ensure you have all the pieces you need in the box before you start assembling the bookshelf. The compiler uses the function prototypes in the same way before it starts assembling your program.
If you're following along with the sample.c program we looked at earlier, open and edit the file to add a function prototype, function definition and function call for the doubleAndAdd function shown here. Then, compile and run your program as before to see how the new code works. You can use the following code as a guide to try it out:
#include
int doubleAndAdd(int, int);
int main()
{
printf("This is output from my first program!\n");
printf("If you double then add 2 and 3, the result is: %d \n", doubleAndAdd(2,3));
return 0;
}
int doubleAndAdd(int a, int b)
{
return ((2*a)+(2*b));
}
So far we've looked at some basic structural elements in a C program. Now, let's look at the types of data you can work with in a C program and what operations you can perform on that data.
Function Declarations
In C, you'll probably hear the term function declaration more than function prototype, especially among older C programmers. We're using the term function prototype in this article, though, because it has an important distinction. Originally, a function declaration did not require any parameters, so the return type, function name and a pair of empty parentheses were sufficient. A function prototype, though, gives the compiler important additional information by including the number and data types of the parameters it will call. Prototypes have become a best practice approach among coders today, in C and other programming languages.
Data Types and Operations in C

From your computer's perspective, data is nothing but a series of ones and zeros representing on and off states for the electronic bits on your hard drive or in your computer's processor or memory. It's the software you're running on a computer that determines how to make sense of those billions of binary digits. C is one of few high-level languages that can easily manipulate data at the bit level in addition to interpreting the data based on a given data type.
A data type is a small set of rules that indicate how to make sense of a series of bits. The data type has a specific size plus its own way of performing operations (such as adding and multiplying) on data of that type. In C, the size of the data type is related to the processor you're using. For example, in C99, a piece of data of the integer data type (int) is 16 bits long in a 16-bit processor while for 32-bit and 64-bit processors it's 32 bits long.
Another important thing for C programmers to know is how the language handles signed and unsigned data types. A signed type means that one of its bits is reserved as the indicator for whether it's a positive or negative number. So, while an unsigned int on a 16-bit system can handle numbers between 0 and 65,535, a signed in on the same system can handle numbers between -32,768 and 32,767. If an operation causes an int variable to go beyond its range, the programmer has to handle the overflow with additional code.
Given these constraints and system-specific peculiarities in C data types and operations, C programmers must choose their data types based on the needs of their programs. Some of the data types they can choose are the primitive data types in C, meaning those built in to the C programming language. Look to your favorite C programming guide for a complete list of the data types in C and important information about how to convert data from one type to another.
C programmers can also create data structures, which combine primitive data types and a set of functions that define how the data can be organized and manipulated. Though the use of data structures is an advanced programming topic and beyond the scope of this article, we will take a look at one of the most common structures: arrays. An array is a virtual list containing pieces of data that are all the same data type. An array's size can't be changed, though its contents can be copied to other larger or smaller arrays.
Though programmers often use arrays of numbers, character arrays, called strings, have the most unique features. A string allows you to save something you might say (like "hello") into a series of characters, which your C program can read in from the user or print out on the screen. String manipulation has such a unique set of operations, it has its own dedicated C library (string.h) with your typical string functions.
The built-in operations in C are the typical operations you'd find in most programming languages. When you're combining several operations into a single statement, be sure to know the operator precedence, or the order in which the program will perform each operation in a mathematical expression. For example, (2+5)*3 equals 21 while 2+5*3 equals 17, because C will perform multiplication before addition unless there are parentheses indicating otherwise.
If you're learning C, make it a priority to familiarize yourself with all of its primitive data types and operations and the precedence for operations in the same expression. Also, experiment with different operations on variables and numbers of different data types.
At this point, you've scratched the surface of some important C basics. Next, though, let's look at how C enables you to write programs without starting from scratch every time.
Don't Start from Scratch, Use Libraries
Libraries are very important in C because the C language supports only the most basic features that it needs. For example, C doesn't contain input-output (I/O) functions to read from the keyboard and write to the screen. Anything that extends beyond the basics must be written by a programmer. If the chunk of code is useful to multiple different programs, it's often put into a library to make it easily reusable.
In our discussion of C so far, we've already seen one library, the standard I/O (stdio) library. The #include line at the beginning of the program instructed the C compiler to loaded the library from its header file named stdio.h. C maintainers include standard C libraries for I/O, mathematical functions, time manipulation and common operations on certain data structures, such as a string of characters. Search the Web or your favorite C programming guide for information about the C89 standard library and the updates and additions in C99.
You, too, can write C libraries. By doing so, you can split your program into reusable modules. This modular approach not only makes it easy to include the same code in multiple programs, but it also makes for shorter program files which are easier to read, test and debug.
To use the functions within a header file, add a #include line for it at the beginning of your program. For standard libraries, put the name of the library's corresponding header file between greater-than and less-than signs (). For libraries you create yourself, put the name of the file between double quotes. Unlike statements in other parts of your C program, you don't have to put a semicolon at the end of each line. The following shows including one of each type of library:
#include
#include "mylib.h"
A comprehensive C programming source should provide the instructions you need to write your own libraries in C. The function definitions you'll write are not any different whether they're in a library or in your main program. The difference is that you'll compile them separately in something called an object file (with a name ending in .o), and you'll create a second file, called a header file (with a name ending in .h) which contains the function prototypes corresponding to each function in the library. It's the header file you'll reference in your #include line in each main program that uses your library, and you'll include the object file as an argument in the compiler command each time you compile that program.
The C features we've explored so far are typical in other programming languages, too. Next, though, we'll talk about how C manages your computer's memory.
Some Pointers about Pointers in C
When your C program is loaded into memory (typically the random-access memory, or RAM, in your computer), each piece of the program is associated with an address in memory. This includes the variables you're using to hold certain data. Each time your program calls a function, it loads that function and all of its associated data into memory just long enough to run that function and return a value. If you pass parameters to the function, C automatically makes a copy of the value to use in the function.
Sometimes when you run a function, though, you want to make some permanent change to the data at its original memory location. If C makes a copy of data to use in the function, the original data remains unchanged. If you want to change that original data, you have to pass a pointer to its memory address (pass by reference) instead of passing its value to the function (pass by value).
Pointers are used everywhere in C, so if you want to use the C language fully you have to have a good understanding of pointers. A pointer is a variable like other variables, but its purpose is to store the memory address of some other data. The pointer also has a data type so it knows how to recognize the bits at that memory address.
When you look at two variables side-by-side in C code, you may not always recognize the pointer. This can be a challenge for even the most experienced C programmers. When you first create a pointer, though, it's more obvious because there must be an asterisk immediately before the variable name. This is known as the indirection operator in C. The following example code creates an integer i and a pointer to an integer p:
int i;
int *p;
Currently there is no value assigned to either i or p. Next, let's assign a value to i and then assign p to point to the address of i.
i = 3;
p = &i;
Here you can see the ampersand (&) used as the address operator immediately before i, meaning the "address of i." You don't have to know what that address is to make the assignment. That's good, because it will likely be different every time you run the program! Instead, the address operator will determine the address associated with that variable while the program is running. Without the address operator, the assignment p=i would assign p the memory address of 3, literally, rather than the memory address of the variable i.
Next, let's look at how you can use pointers in C code and the challenges you'll want to be prepared for.
Using Pointers Correctly in C

Once you have a pointer, you can use that in place of a variable of the same data type in operations and function calls. In the following example, the pointer to i is used instead of i within a larger operation. The asterisk used with the p (*p) indicates that the operation should use the value that p is pointing to at that memory address, not the memory address itself:
int b;
b = *p + 2;
Without pointers, it's nearly impossible to divide tasks into functions outside of main in your C program. To illustrate this, consider you've created a variable in main called h that stores the user's height to the nearest centimeter. You also call a function you've written named setHeight that prompts the user to set that height value. The lines in your main function might look something like this:
int h;
setHeight(h); /* There is a potential problem here. */
This function call will try to pass the value of h to setHeight. However, when the function finishes running, the value of h will be unchanged because the function only used a copy of it and then discarded it when it finished running.
If you want to change h itself, you should first ensure that the function can take a pointer to an existing value rather than a new copy of a value. The first line of setHeight, then, would use a pointer instead of a value as its parameter (note the indirection operator):
setHeight(int *height) { /* Function statements go here */ }
Then, you have two choices for calling setHeight. The first is to use the address operator for h as the passed parameter (&h). The other is to create a separate pointer to h and pass that instead. The following shows both options:
setHeight(&h); /* Übergebe die Adresse von h an die Funktion */
int *p;
p = &h;
setHöhe (p); /* Einen separaten Zeiger auf die Adresse von h an die Funktion übergeben */
Die zweite Option offenbart eine häufige Herausforderung bei der Verwendung von Zeigern. Die Herausforderung besteht darin, mehrere Zeiger auf denselben Wert zu haben. Das bedeutet, dass jede Änderung an diesem einen Wert alle seine Zeiger gleichzeitig betrifft. Dies kann gut oder schlecht sein, je nachdem, was Sie mit Ihrem Programm erreichen möchten. Auch hier ist die Beherrschung der Verwendung von Zeigern ein wichtiger Schlüssel zur Beherrschung der C-Programmierung. Üben Sie so viel wie möglich mit Zeigern, damit Sie bereit sind, sich diesen Herausforderungen zu stellen.
Die C-Funktionen, die wir bisher untersucht haben, sind auch für andere Programmiersprachen typisch. Als nächstes werden wir uns jedoch die Anforderungen von C für eine sorgfältige Speicherverwaltung ansehen.
Die Bedeutung der Speicherverwaltung in C
Eines der Dinge, die C zu einer so vielseitigen Sprache machen, ist, dass der Programmierer ein Programm so herunterskalieren kann, dass es mit sehr wenig Speicher ausgeführt wird. Als C zum ersten Mal geschrieben wurde, war dies ein wichtiges Feature, da Computer nicht annähernd so leistungsfähig waren wie heute. Angesichts der aktuellen Nachfrage nach kleiner Elektronik, von Mobiltelefonen bis hin zu winzigen medizinischen Geräten, besteht ein erneutes Interesse daran, die Speicheranforderungen für einige Software gering zu halten. C ist die bevorzugte Sprache für die meisten Programmierer, die viel Kontrolle über die Speichernutzung benötigen.
Um die Bedeutung der Speicherverwaltung besser zu verstehen, betrachten Sie, wie ein Programm Speicher verwendet. Wenn Sie ein Programm zum ersten Mal ausführen, wird es in den Speicher Ihres Computers geladen und beginnt mit der Ausführung, indem es Anweisungen vom Prozessor des Computers sendet und empfängt. Wenn das Programm eine bestimmte Funktion ausführen muss, lädt es diese Funktion für die Dauer der Ausführung in einen weiteren Teil des Speichers und verlässt diesen Speicher dann, wenn die Funktion abgeschlossen ist. Außerdem beansprucht jedes neue Datenelement, das im Hauptprogramm verwendet wird, für die Dauer des Programms Speicherplatz.
Wenn Sie all dies besser steuern möchten, benötigen Sie eine dynamische Speicherzuweisung. C unterstützt die dynamische Speicherzuweisung, d. h. die Möglichkeit, Speicher nach Bedarf zu reservieren und diesen Speicher freizugeben, sobald Sie ihn nicht mehr verwenden. Viele Programmiersprachen verfügen über eine automatische Speicherzuweisung und Speicherbereinigung, die diese Speicherverwaltungsaufgaben handhaben. C erlaubt (und erfordert in einigen Fällen) jedoch, dass Sie die Speicherzuweisung mit den folgenden Schlüsselfunktionen aus der Standard-C-Bibliothek explizit angeben:
- malloc – Abkürzung für Memory Allocation, malloc wird verwendet, um einen Speicherblock einer bestimmten Größe zu reservieren, um eine bestimmte Art von Daten zu speichern, die Ihr Programm verarbeiten muss. Wenn Sie malloc verwenden, erstellen Sie einen Zeiger auf den zugewiesenen Speicher. Dies ist nicht notwendig für ein einzelnes Datenelement, wie z. B. eine ganze Zahl, die zugewiesen wird, sobald Sie es zum ersten Mal deklarieren (wie in int i). Es ist jedoch ein wichtiger Bestandteil beim Erstellen und Verwalten von Datenstrukturen wie Arrays. Alternative Speicherzuweisungsoptionen in C sind calloc , das auch den Speicher löscht, wenn er reserviert ist, und realloc , das die Größe des zuvor reservierten Speichers ändert.
- free -- Verwenden Sie free, um Ihr Programm zu zwingen, den zuvor einem bestimmten Zeiger zugewiesenen Speicher freizugeben.
Best Practice bei der Verwendung von malloc und free ist, dass alles, was Sie zuweisen, freigegeben werden sollte. Immer wenn Sie etwas zuweisen, auch in einer temporären Funktion, bleibt es im Speicher, bis das Betriebssystem den Speicherplatz bereinigt. Um sicherzustellen, dass Speicher frei und sofort einsatzbereit ist, sollten Sie ihn freigeben, bevor die aktuelle Funktion beendet wird. Diese Speicherverwaltung bedeutet, dass Sie den Speicherbedarf Ihres Programms auf ein Minimum reduzieren und Speicherlecks vermeiden können. Ein Speicherleck ist ein Programmfehler, bei dem immer mehr Speicher verwendet wird, bis kein Speicher mehr verfügbar ist, wodurch das Programm blockiert oder abstürzt. Machen Sie sich andererseits nicht so viele Gedanken über das Freigeben von Speicher, dass Sie etwas freigeben und somit etwas verlieren, das Sie später in derselben Funktion benötigen.
In diesem Artikel haben Sie einige der Grundstrukturen und Kernkonzepte der Programmiersprache C kennengelernt. Wir haben uns ihre Geschichte angesehen, die Eigenschaften, die sie mit anderen Programmiersprachen gemeinsam hat, und die wichtigen Merkmale, die sie zu einer einzigartigen und vielseitigen Option für die Codierung von Software machen. Wechseln Sie zur nächsten Seite, um viele weitere Informationen zu erhalten, einschließlich einiger Programmierleitfäden, die Sie auf Ihrer Reise in C weiterführen.
Viele weitere Informationen
Zum Thema passende Artikel
- Die Grundlagen der C-Programmierung
- Wie Java funktioniert
- Wie Boolesche Logik funktioniert
- Wie PERL funktioniert
- Wie das BIOS funktioniert
- Wie CGI-Scripting funktioniert
- Wie Bits und Bytes funktionieren
Weitere tolle Links
- C-Programming.com-Tutorial
- C-Programmierung bei Wikibooks
- GNU-Compiler-Sammlung (GCC)
- Eclipse-Software für die integrierte Entwicklungsumgebung
Quellen
- Kernighan, Brian W. und Ritchie, Dennis M. „C-Programmiersprache, zweite Ausgabe.“ Lehrlingshalle. 1988.
- King, KN "C-Programmierung: Ein moderner Ansatz, Zweite Auflage." WW Norton & Company, Inc. 2008.