Was sind überzeugende Beispiele, in denen die Zeigerarithmetik der Array-Subskribierung vorzuziehen ist?

9

Ich bereite einige Folien für eine einführende C-Klasse vor, und ich versuche, gute Beispiele (und Motivation) für die Verwendung von Zeigerarithmetik über Array-Subskriptionen zu präsentieren.

Viele Beispiele, die ich in Büchern sehe, sind ziemlich gleichwertig. Zum Beispiel zeigen viele Bücher, wie man die Groß- und Kleinschreibung aller Werte in einer Zeichenkette umkehrt, aber mit der Ausnahme, dass a [i] durch ein * p ersetzt wird, ist der Code identisch.

Ich suche nach einem guten (und kurzen) Beispiel mit eindimensionalen Arrays, bei denen die Zeigerarithmetik wesentlich eleganteren Code erzeugen kann. Irgendwelche Ideen?

    
Uri 28.03.2009, 17:19
quelle

9 Antworten

15

Erneut einen Zeiger anstelle eines Werts abrufen:

Normalerweise verwendet man Zeigerarithmetik, wenn sie wieder einen Zeiger bekommen wollen. Um einen Zeiger zu erhalten, während ein Array-Index verwendet wird: 1) Berechnen des Zeiger-Offsets, dann 2) Abrufen des Wertes an diesem Speicherort, dann 3) Sie müssen & amp; um die Adresse wieder zu bekommen. Das ist mehr Eingabe und weniger saubere Syntax.

Beispiel 1: Angenommen, Sie benötigen einen Zeiger auf das 512. Byte in einem Puffer

%Vor%

Ist sauberer als:

%Vor%

Beispiel 2: Effizienter strcat

%Vor%

Das ist sauberer als:

%Vor%

Verwenden der Zeigerarithmetik ++ als Iterator:

Das Inkrementieren von Zeigern mit ++ und das Dekrementieren mit - ist nützlich, wenn über jedes Element in einem Array von Elementen iteriert wird. Es ist sauberer als eine separate Variable zu verwenden, um den Offset zu verfolgen.

Zeiger-Subtraktion:

Sie können die Zeiger-Subtraktion mit Zeigerarithmetik verwenden. Dies kann in einigen Fällen nützlich sein, um das Element vor demjenigen zu erhalten, auf das Sie zeigen. Es kann auch mit Array-Indizes gemacht werden, aber es sieht wirklich schlecht und verwirrend aus. Vor allem für einen Python-Programmierer, wo ein negativer Index angegeben wird, um etwas vom Ende der Liste zu indizieren.

    
Brian R. Bondy 28.03.2009, 17:23
quelle
3
%Vor%

Warum möchten Sie solch eine Schönheit mit einem Index verwöhnen? (Siehe K & amp; R, und wie sie auf diesem Stil aufbauen.) Es gibt einen Grund, warum ich die obige Signatur so verwendet habe, wie sie ist. Beende die Bearbeitung, ohne vorher um eine Klarstellung zu bitten. Für diejenigen, die denken, dass sie es wissen, schauen Sie sich die aktuelle Unterschrift an - Sie haben einige restrict Qualifikationen verpasst.

Strukturausrichtungstest und die offsetof Makroimplementierung.

    
dirkgently 28.03.2009 17:23
quelle
1
___ answer693149 ___
%Vor%

Warum möchten Sie solch eine Schönheit mit einem Index verwöhnen? (Siehe K & amp; R, und wie sie auf diesem Stil aufbauen.) Es gibt einen Grund, warum ich die obige Signatur so verwendet habe, wie sie ist. Beende die Bearbeitung, ohne vorher um eine Klarstellung zu bitten. Für diejenigen, die denken, dass sie es wissen, schauen Sie sich die aktuelle Unterschrift an - Sie haben einige %code% Qualifikationen verpasst.

Strukturausrichtungstest und die %code% Makroimplementierung.

    
___ qstntxt ___

Ich bereite einige Folien für eine einführende C-Klasse vor, und ich versuche, gute Beispiele (und Motivation) für die Verwendung von Zeigerarithmetik über Array-Subskriptionen zu präsentieren.

Viele Beispiele, die ich in Büchern sehe, sind ziemlich gleichwertig. Zum Beispiel zeigen viele Bücher, wie man die Groß- und Kleinschreibung aller Werte in einer Zeichenkette umkehrt, aber mit der Ausnahme, dass a [i] durch ein * p ersetzt wird, ist der Code identisch.

Ich suche nach einem guten (und kurzen) Beispiel mit eindimensionalen Arrays, bei denen die Zeigerarithmetik wesentlich eleganteren Code erzeugen kann. Irgendwelche Ideen?

    
___ answer693172 ___

Wenn Sie einen alten Compiler oder irgendeinen spezialisierten Compiler für eingebettete Systeme verwenden, könnte es kleine Leistungsunterschiede geben, aber die meisten modernen Compiler würden wahrscheinlich diese (winzigen) Unterschiede optimieren.

Der folgende Artikel könnte etwas sein, auf das Sie zurückgreifen könnten - hängt vom Niveau Ihrer Schüler ab:

Ссылка

    
___ qstnhdr ___ Was sind überzeugende Beispiele, in denen die Zeigerarithmetik der Array-Subskribierung vorzuziehen ist? ___ answer1573212 ___

Zeigerarithmetik mag schick und "hackerisch" aussehen, aber ich habe nie einen Fall gefunden, der SCHNELLER war als die Standardindexierung. Im Gegenteil, ich bin oft auf Fälle gestoßen, in denen der Code stark verlangsamt wurde.

Beispielsweise ist eine typische sequenzielle Schleife durch ein Array mit einem Zeiger möglicherweise weniger effizient als eine Schleife mit einem klassischen Index auf einem modernen Prozessor, der SSE-Erweiterungen unterstützt. Die Pointer-Arithmetik in einer Schleife blockiert Compiler ausreichend, um eine Loop-Vektorisierung durchzuführen, was eine typische 2x-4x-Leistungsverstärkung ergeben kann. Außerdem kann die Verwendung von Zeigern anstelle von einfachen Ganzzahlvariablen zu unnötigen Speicheroperationen aufgrund von Zeigeraliasbildung führen.

Daher sollte im Allgemeinen die Zeigerarithmetik anstelle des standardmäßigen indizierten Zugriffs NIE empfohlen werden.

    
___ answer693282 ___

Sie fragen spezifisch nach C, aber C ++ baut auch darauf auf:

Die meisten Zeigerarithmetik verallgemeinert sich natürlich auf das Forward-Iterator-Konzept. Das Durchlaufen des Speichers mit %code% kann für jeden Sequenz-Container (verknüpfte Liste, Skip-Liste, Vektor, Binärbaum, B-Baum usw.) verwendet werden, da der Operator überlastet ist.

    
___ answer7105880 ___
%Vor%     
___ answer693253 ___

Oft ist die Wahl nur eine von Stil - man sieht oder fühlt sich natürlicher als die anderen für einen bestimmten Fall.

Es gibt auch das Argument, dass die Verwendung von Indizes dazu führen kann, dass der Compiler Offsets innerhalb einer Schleife wiederholt neu berechnen muss - ich bin nicht sicher, wie oft das der Fall ist (anders als in nicht optimierten Builds), aber ich stelle es mir vor passiert, aber es ist wahrscheinlich selten ein Problem.

Ein Bereich, der meiner Meinung nach auf lange Sicht wichtig ist (was vielleicht nicht für eine einführende C-Klasse gilt - aber lerne sie früh, sage ich), ist, dass Zeigerarithmetik auf die in C ++ STL verwendeten Idiome angewendet wird. Wenn Sie sie dazu bringen, die Zeigerarithmetik zu verstehen und sie zu verwenden, werden sie, wenn sie mit der STL fortfahren, einen Anhaltspunkt dafür haben, wie man Iteratoren richtig einsetzt.

    
___ tag123c ___ C ist eine universelle Computerprogrammiersprache, die für Betriebssysteme, Bibliotheken, Spiele und andere Hochleistungsanwendungen verwendet wird. Dieses Tag sollte bei allgemeinen Fragen zur C-Sprache verwendet werden, wie in der Norm ISO 9899: 2011 definiert. Fügen Sie ggf. ein versionsspezifisches Tag wie c99 oder c90 für Fragen zu älteren Sprachstandards hinzu. C unterscheidet sich von C ++ und es sollte nicht mit dem C ++ - Tag kombiniert werden, wenn ein rationaler Grund fehlt. ___ tag123pointerarithmetic ___ Sie können eine begrenzte Anzahl arithmetischer Operationen auf Zeigern ausführen. Diese Operationen sind: Inkrement, Dekrement, Addition, Subtraktion, Vergleich und Zuweisung. ___ answer693287 ___

Etwas Spaß, ich hoffe, Sie müssen nie damit umgehen: Zeiger können Alias, während Arrays nicht können. Aliasing kann alle Arten von nicht-idealen Codegenerierung verursachen, von denen die häufigste einen Zeiger als out-Parameter für eine andere Funktion verwendet. Grundsätzlich kann der Compiler nicht davon ausgehen, dass der von der Funktion verwendete Zeiger sich selbst oder irgendetwas anderes in diesem Stapelrahmen nicht aliasiert, so dass er den Wert jedes Mal, wenn er verwendet wird, vom Zeiger neu laden muss. Oder besser gesagt, um sicher zu gehen.

    
___ answer693148 ___

Erneut einen Zeiger anstelle eines Werts abrufen:

Normalerweise verwendet man Zeigerarithmetik, wenn sie wieder einen Zeiger bekommen wollen. Um einen Zeiger zu erhalten, während ein Array-Index verwendet wird: 1) Berechnen des Zeiger-Offsets, dann 2) Abrufen des Wertes an diesem Speicherort, dann 3) Sie müssen & amp; um die Adresse wieder zu bekommen. Das ist mehr Eingabe und weniger saubere Syntax.

Beispiel 1: Angenommen, Sie benötigen einen Zeiger auf das 512. Byte in einem Puffer

%Vor%

Ist sauberer als:

%Vor%

Beispiel 2: Effizienter strcat

%Vor%

Das ist sauberer als:

%Vor%

Verwenden der Zeigerarithmetik ++ als Iterator:

Das Inkrementieren von Zeigern mit ++ und das Dekrementieren mit - ist nützlich, wenn über jedes Element in einem Array von Elementen iteriert wird. Es ist sauberer als eine separate Variable zu verwenden, um den Offset zu verfolgen.

Zeiger-Subtraktion:

Sie können die Zeiger-Subtraktion mit Zeigerarithmetik verwenden. Dies kann in einigen Fällen nützlich sein, um das Element vor demjenigen zu erhalten, auf das Sie zeigen. Es kann auch mit Array-Indizes gemacht werden, aber es sieht wirklich schlecht und verwirrend aus. Vor allem für einen Python-Programmierer, wo ein negativer Index angegeben wird, um etwas vom Ende der Liste zu indizieren.

    
___
Aditya Mukherji 28.03.2009 17:26
quelle
1

Wenn Sie einen alten Compiler oder irgendeinen spezialisierten Compiler für eingebettete Systeme verwenden, könnte es kleine Leistungsunterschiede geben, aber die meisten modernen Compiler würden wahrscheinlich diese (winzigen) Unterschiede optimieren.

Der folgende Artikel könnte etwas sein, auf das Sie zurückgreifen könnten - hängt vom Niveau Ihrer Schüler ab:

Ссылка

    
dommer 28.03.2009 17:33
quelle
1

Sie fragen spezifisch nach C, aber C ++ baut auch darauf auf:

Die meisten Zeigerarithmetik verallgemeinert sich natürlich auf das Forward-Iterator-Konzept. Das Durchlaufen des Speichers mit *p++ kann für jeden Sequenz-Container (verknüpfte Liste, Skip-Liste, Vektor, Binärbaum, B-Baum usw.) verwendet werden, da der Operator überlastet ist.

    
Tom 28.03.2009 18:39
quelle
1

Zeigerarithmetik mag schick und "hackerisch" aussehen, aber ich habe nie einen Fall gefunden, der SCHNELLER war als die Standardindexierung. Im Gegenteil, ich bin oft auf Fälle gestoßen, in denen der Code stark verlangsamt wurde.

Beispielsweise ist eine typische sequenzielle Schleife durch ein Array mit einem Zeiger möglicherweise weniger effizient als eine Schleife mit einem klassischen Index auf einem modernen Prozessor, der SSE-Erweiterungen unterstützt. Die Pointer-Arithmetik in einer Schleife blockiert Compiler ausreichend, um eine Loop-Vektorisierung durchzuführen, was eine typische 2x-4x-Leistungsverstärkung ergeben kann. Außerdem kann die Verwendung von Zeigern anstelle von einfachen Ganzzahlvariablen zu unnötigen Speicheroperationen aufgrund von Zeigeraliasbildung führen.

Daher sollte im Allgemeinen die Zeigerarithmetik anstelle des standardmäßigen indizierten Zugriffs NIE empfohlen werden.

    
user190707 15.10.2009 15:44
quelle
1
%Vor%     
xxx 18.08.2011 10:21
quelle
0

Oft ist die Wahl nur eine von Stil - man sieht oder fühlt sich natürlicher als die anderen für einen bestimmten Fall.

Es gibt auch das Argument, dass die Verwendung von Indizes dazu führen kann, dass der Compiler Offsets innerhalb einer Schleife wiederholt neu berechnen muss - ich bin nicht sicher, wie oft das der Fall ist (anders als in nicht optimierten Builds), aber ich stelle es mir vor passiert, aber es ist wahrscheinlich selten ein Problem.

Ein Bereich, der meiner Meinung nach auf lange Sicht wichtig ist (was vielleicht nicht für eine einführende C-Klasse gilt - aber lerne sie früh, sage ich), ist, dass Zeigerarithmetik auf die in C ++ STL verwendeten Idiome angewendet wird. Wenn Sie sie dazu bringen, die Zeigerarithmetik zu verstehen und sie zu verwenden, werden sie, wenn sie mit der STL fortfahren, einen Anhaltspunkt dafür haben, wie man Iteratoren richtig einsetzt.

    
Michael Burr 28.03.2009 18:22
quelle
0

Etwas Spaß, ich hoffe, Sie müssen nie damit umgehen: Zeiger können Alias, während Arrays nicht können. Aliasing kann alle Arten von nicht-idealen Codegenerierung verursachen, von denen die häufigste einen Zeiger als out-Parameter für eine andere Funktion verwendet. Grundsätzlich kann der Compiler nicht davon ausgehen, dass der von der Funktion verwendete Zeiger sich selbst oder irgendetwas anderes in diesem Stapelrahmen nicht aliasiert, so dass er den Wert jedes Mal, wenn er verwendet wird, vom Zeiger neu laden muss. Oder besser gesagt, um sicher zu gehen.

    
MSN 28.03.2009 18:44
quelle

Tags und Links