Solution de Adresse IPv4 - Sujet 22 - EP NSI 2025

Moyen Officiel
Python (3.14.0)

Énoncé du problème

Exercice 1

EXERCICE 1 (10 points)

Écrire une fonction recherche qui prend en paramètres elt un nombre entier et tab un tableau de nombres entiers (type list), et qui renvoie l’indice de la dernière occurrence de elt dans tab si elt est dans tab et None sinon.

Exemples :

>>> recherche(1, [2, 3, 4]) # renvoie None
>>> recherche(1, [10, 12, 1, 56])
2
>>> recherche(1, [1, 0, 42, 7])
0
>>> recherche(1, [1, 50, 1])
2
>>> recherche(1, [8, 1, 10, 1, 7, 1, 8])
5

Exercice 2

EXERCICE 2 (10 points)

On définit une classe gérant une adresse IPv4.

On rappelle qu’une adresse IPv4 est une adresse de longueur 4 octets, notée en décimale à point, en séparant chacun des octets par un point. On considère un réseau privé avec une plage d’adresses IP de 192.168.0.0 à 192.168.0.255.

On considère que les adresses IP saisies sont valides.

Les adresses IP 192.168.0.0 et 192.168.0.255 sont des adresses réservées.

Le code ci-dessous implémente la classe AdresseIP.

class AdresseIP:
    def __init__(self, adresse):
        self.adresse =... 

    def liste_octets(self):
        """renvoie une liste de nombres entiers,
        la liste des octets de l'adresse IP"""
        # Note : split découpe la chaine de caractères 
        # en fonction du séparateur
        return [int(i) for i in self.adresse.split(".")]

    def est_reservee(self):
        """renvoie True si l'adresse IP est une adresse
        réservée, False sinon"""
        reservees = [ ... ] 
        return ... 

    def adresse_suivante(self):
        """renvoie un objet de AdresseIP avec l'adresse
        IP qui suit l'adresse self si elle existe et None sinon"""
        octets = ... 
        if ... == 254: 
            return None
        octet_nouveau = ... + ... 
        return AdresseIP('192.168.0.' + ...) 

Compléter le code ci-dessus et instancier trois objets : adresse1, adresse2, adresse3 avec respectivement les arguments suivants :

'192.168.0.1','192.168.0.2','192.168.0.0'

Vérifier que :

>>> adresse1.liste_octets()
[192, 168, 0, 1]
>>> adresse1.est_reservee()
False
>>> adresse3.est_reservee()
True
>>> adresse2.adresse_suivante().adresse # acces valide à adresse
                # ici car on sait que l'adresse suivante existe
'192.168.0.3'

Les contraintes ci-dessous sont ajoutées par la plateforme et ne font pas partie du sujet.

Exercice 1

Contraintes :

  • elt est un nombre entier (int)
  • tab est un tableau (list) de nombres entiers, éventuellement vide
  • 0 <= len(tab) <= 10^4
  • -10^9 <= elt <= 10^9 et -10^9 <= tab[i] <= 10^9
  • tab n’est pas nécessairement trié et peut contenir plusieurs fois la même valeur
  • la fonction renvoie l’indice de la dernière occurrence de elt, et None si elt n’apparaît pas dans tab (en particulier si tab est vide)

Exercice 2

Contraintes :

  • adresse est une chaîne de caractères (str) de la forme '192.168.0.x' avec 0 <= x <= 255, écrite sans zéro initial
  • toutes les adresses fournies sont valides : aucune vérification de validité n’est demandée
  • liste_octets renvoie une liste de 4 nombres entiers compris entre 0 et 255
  • les adresses réservées sont exactement 192.168.0.0 et 192.168.0.255
  • adresse_suivante renvoie None lorsque le dernier octet vaut 254, et sinon un objet AdresseIP dont l’attribut adresse est l’adresse suivante
  • le comportement de adresse_suivante sur 192.168.0.255 n’est pas spécifié par le sujet et n’est pas évalué

Solution

Exercice 1 - indice de la dernière occurrence

L’idée. On cherche la dernière fois que elt apparaît dans tab. Le plus simple est de parcourir le tableau du début à la fin en retenant dans une variable l’indice de chaque occurrence rencontrée. Chaque nouvelle occurrence écrase la précédente : quand la boucle est terminée, la variable contient donc l’indice de la dernière. Si on n’a jamais rien trouvé, elle vaut encore None, ce qui est exactement la réponse attendue.

Un petit exemple. Pour recherche(1, [8, 1, 10, 1, 7, 1, 8]), la variable prend successivement la valeur 1, puis 3, puis 5. À la fin de la boucle elle vaut 5 : c’est la réponse.

def recherche(elt, tab):
    indice = None
    # On parcourt tout le tableau : chaque occurrence trouvée remplace la
    # précédente, donc à la fin indice retient bien la dernière
    for i in range(len(tab)):
        if tab[i] == elt:
            indice = i
    return indice

indice est initialisé à None : c’est la valeur qu’on renverra si aucune case ne contient elt, et cela règle du même coup le cas du tableau vide, où la boucle ne s’exécute pas du tout. On boucle sur range(len(tab)) et non sur les valeurs, parce que c’est l’indice i qui nous intéresse, pas le contenu. Surtout, on ne s’arrête pas à la première occurrence : il faut aller jusqu’au bout du tableau pour être sûr d’avoir vu la dernière.

Variante : on peut aussi parcourir le tableau à l’envers et renvoyer le premier indice trouvé, mais il faut alors penser à renvoyer None après la boucle.

Exercice 2 - la classe AdresseIP

L’idée. Il y a quatre trous à compléter, et chacun est court.

  • __init__ doit simplement ranger la chaîne reçue dans l’attribut self.adresse, puisque toutes les autres méthodes s’en servent.
  • est_reservee : les deux seules adresses réservées sont 192.168.0.0 et 192.168.0.255. On les place dans la liste reservees, puis on demande avec in si self.adresse s’y trouve.
  • adresse_suivante : dans ce réseau, seul le dernier octet change. On récupère les octets avec liste_octets() et on regarde le dernier, octets[3]. S’il vaut 254, l’adresse suivante serait 192.168.0.255, qui est réservée : on renvoie None. Sinon on ajoute 1 à ce dernier octet et on construit une nouvelle AdresseIP.

Un petit exemple. Pour 192.168.0.2, liste_octets() donne [192, 168, 0, 2], le dernier octet vaut 2, il n’est pas égal à 254, donc le nouvel octet vaut 3 et on renvoie une AdresseIP d’adresse '192.168.0.3'.

class AdresseIP:
    def __init__(self, adresse):
        self.adresse = adresse

    def liste_octets(self):
        """renvoie une liste de nombres entiers,
        la liste des octets de l'adresse IP"""
        # Note : split découpe la chaine de caractères
        # en fonction du séparateur
        return [int(i) for i in self.adresse.split(".")]

    def est_reservee(self):
        """renvoie True si l'adresse IP est une adresse
        réservée, False sinon"""
        reservees = ['192.168.0.0', '192.168.0.255']
        return self.adresse in reservees

    def adresse_suivante(self):
        """renvoie un objet de AdresseIP avec l'adresse
        IP qui suit l'adresse self si elle existe et None sinon"""
        octets = self.liste_octets()
        # Seul le dernier octet change : s'il vaut 254, l'adresse suivante
        # serait 192.168.0.255, qui est réservée
        if octets[3] == 254:
            return None
        octet_nouveau = octets[3] + 1
        return AdresseIP('192.168.0.' + str(octet_nouveau))

Quelques points de vigilance. Dans est_reservee, la comparaison porte sur la chaîne self.adresse : les éléments de reservees sont donc bien des chaînes entre guillemets, pas des nombres. Dans adresse_suivante, octets est une liste de quatre entiers et octets[3] en est le dernier, celui des unités. Enfin octet_nouveau est un entier alors qu’on veut construire une chaîne : la conversion par str(octet_nouveau) est indispensable, sans elle Python refuse d’additionner une chaîne et un entier.

Pour vérifier, on crée les trois objets demandés par le sujet :

adresse1 = AdresseIP('192.168.0.1')
adresse2 = AdresseIP('192.168.0.2')
adresse3 = AdresseIP('192.168.0.0')

et on retrouve les résultats attendus : adresse1.liste_octets() vaut [192, 168, 0, 1], adresse1.est_reservee() vaut False, adresse3.est_reservee() vaut True, et adresse2.adresse_suivante().adresse vaut '192.168.0.3'.