C programa para crear e imprimir una lista vinculada desde la línea de comandos -- ampo con linked-list campo con console camp codereview Relacionados El problema

C program to create and print a linked list from the command line


5
vote

problema

Español

Este programa creará una lista vinculada, establecerá los valores e imprimirá la lista usando las opciones de línea de comandos.

Esta es mi primera implementación de una lista vinculada, así que no estoy seguro si lo hice correctamente. Las opciones disponibles son:

var Module = (function () { var markers = []; var contentsBefSort = []; var infoWindows = []; var contentsNew = []; var ready = false; //model data var locations = [{ name: 'Le Thai', coords: { lat: 36.168743, lng: -115.139866 } }, { name: 'Atomic Liquors', coords: { lat: 36.166782, lng: -115.13551 } }, { name: 'The Griffin', coords: { lat: 36.168785, lng: -115.140329 } }, { name: 'Pizza Rock', coords: { lat: 36.17182, lng: -115.142304 } }, { name: 'The Mob Museum', coords: { lat: 36.172815, lng: -115.141242 } }, { name: "Joe Vicari's Andiamo Italian Steakhouse", coords: { lat: 36.169437, lng: -115.142903 } }, { name: 'eat.', coords: { lat: 36.166535, lng: -115.139067 } }, { name: "Hugo's Cellar", coords: { lat: 36.169915, lng: -115.143861 } }, { name: 'Therapy', coords: { lat: 36.169041, lng: -115.139829 } }, { name: 'VegeNation', coords: { lat: 36.167401, lng: -115.139453 } } ]; //convert array to JSON var jsonStr = JSON.stringify(locations); $.ajax({ url: 'https://gentle-fortress-70127.herokuapp.com/p', type: "POST", contentType: "application/json", // <==== data: jsonStr, success: function (data) { $.each(data, function (i, location) { var htmlStr = ""; var hours = ""; console.log(location.hours); if (location.hours == false) { hours = "Is closed"; } else { hours = "Is open"; } htmlStr += '<div class ="info">' + '<h2 class="name">' + location.name.toString() + '</h2>' + '<img class="buspic" src=' + location.img + " alt text='bus pic'" + '/>' + '<p class="hours">' + "<b>Open or closed: </b>" + hours + '</p>' + '<p class="reviews">' + "<b>Review count: </b>" + location.revcount + '</p>' + '<p class="rating">' + "<b>Rating: </b>" + location.rating + '</p>' + '<p class="price">' + "<b>Price range: </b>" + location.price + '</p>' + '<p class="location">' + "<b>Address: </b>" + location.location + '</p>' + '<p class="phone">' + "<b>Phone: </b>" + location.phone + '</p>' + '<a href="' + location.url + '">' + 'See more on yelp' + '</a>' + '</div>'; contentsBefSort.push(htmlStr); }); sortArr(contentsBefSort); if (ready) { weatherData(function (data) { console.log(data); var city = data.name; var currWeather = data.weather[0].description; var pic = 'http://openweathermap.org/img/w/' + data.weather[0].icon + '.png'; var currTemp = data.main.temp; var tempHi = data.main.temp_max; var humid = data.main.humidity; var div = '<div class="weatherIn"></div>'; $('body').append(div); $('.weatherIn').append( '<h2>Weather for Downtown ' + city + '</h2>' + '<p>Description: ' + currWeather + '</p>' + '<img src="' + pic + '" alt="Pic here" />' + '<p>Current temperature: ' + currTemp + '&#8457' + '</p>' + '<p>The high for today is ' + tempHi + '&#8457' + '</p>' + '<p>Humidity: ' + humid + '</p>'); }); initMap(); } } }); function sortList() { $('.search').keyup(function (e) { var val = $('.search').val(); var list = $('.btns li'); if (val != "") { $(list).css("display", "none"); $(list).each(function (i) { var h2text = $(this).find('h2').text(); if (h2text.includes(val)) { $(this).css("display", "block"); } }); } else { $(list).css("display", "block"); } }); }; function sortArr(arr) { for (var j = 0; j < locations.length; j++) { for (var i = 0; i < arr.length; i++) { if (arr[i].indexOf(locations[j].name) > -1 || arr[i].indexOf(locations[j].name) == 0) { contentsNew[j] = arr[i]; } } } ready = true; }; function weatherData(callback) { var weather = 'https://api.openweathermap.org/data/2.5/weather?lat=36.168743&lon=-115.139866&units=imperial&APPID=derp'; $.ajax({ dataType: "jsonp", url: weather, success: callback }); }; var initMap = function () { $(' <input type="text" placeholder="Search here" class="search" value="" />').insertBefore('.btns'); if (ready) { var map; map = new google.maps.Map(document.getElementById('map'), { center: { lat: 36.168743, lng: -115.139866 }, zoom: 15 }); for (let i = 0; i < locations.length; i++) { //make markers markers[i] = new google.maps.Marker({ position: new google.maps.LatLng(locations[i].coords.lat, locations[i].coords.lng), map: map, title: locations[i].name }); markers[i].index = i; //add index $('.btns').append('<li>' + contentsNew[i] + '</li>'); var infoWindow = new google.maps.InfoWindow(); infoWindow.setOptions({ maxWidth: 250 }); google.maps.event.addListener(markers[i], 'click', function () { (this.index); infoWindow.setContent([contentsNew[i]].toString()); infoWindow.open(map, markers[this.index]); map.setZoom(16); map.panTo(markers[this.index].getPosition()); }); var list = $('.btns li'); //console.log(list[i]); google.maps.event.addDomListener(list[i], 'click', function () { infoWindow.setContent([contentsNew[i]].toString()); map.setZoom(16); infoWindow.open(map, markers[i]); map.panTo(markers[i].getPosition()); }); var mapCenter = new google.maps.LatLng(36.168743, -115.139866); google.maps.event.addListener(infoWindow, 'closeclick', function () { map.setCenter(mapCenter); map.setZoom(15); }); }; }; sortList(); }; return { initMap: initMap }; })(); 5 para agregar nodos.

Para agregar varios nodos: 99887766555443316 agregará tres nodos con los valores respectivos

var Module = (function () { var markers = []; var contentsBefSort = []; var infoWindows = []; var contentsNew = []; var ready = false; //model data var locations = [{ name: 'Le Thai', coords: { lat: 36.168743, lng: -115.139866 } }, { name: 'Atomic Liquors', coords: { lat: 36.166782, lng: -115.13551 } }, { name: 'The Griffin', coords: { lat: 36.168785, lng: -115.140329 } }, { name: 'Pizza Rock', coords: { lat: 36.17182, lng: -115.142304 } }, { name: 'The Mob Museum', coords: { lat: 36.172815, lng: -115.141242 } }, { name: "Joe Vicari's Andiamo Italian Steakhouse", coords: { lat: 36.169437, lng: -115.142903 } }, { name: 'eat.', coords: { lat: 36.166535, lng: -115.139067 } }, { name: "Hugo's Cellar", coords: { lat: 36.169915, lng: -115.143861 } }, { name: 'Therapy', coords: { lat: 36.169041, lng: -115.139829 } }, { name: 'VegeNation', coords: { lat: 36.167401, lng: -115.139453 } } ]; //convert array to JSON var jsonStr = JSON.stringify(locations); $.ajax({ url: 'https://gentle-fortress-70127.herokuapp.com/p', type: "POST", contentType: "application/json", // <==== data: jsonStr, success: function (data) { $.each(data, function (i, location) { var htmlStr = ""; var hours = ""; console.log(location.hours); if (location.hours == false) { hours = "Is closed"; } else { hours = "Is open"; } htmlStr += '<div class ="info">' + '<h2 class="name">' + location.name.toString() + '</h2>' + '<img class="buspic" src=' + location.img + " alt text='bus pic'" + '/>' + '<p class="hours">' + "<b>Open or closed: </b>" + hours + '</p>' + '<p class="reviews">' + "<b>Review count: </b>" + location.revcount + '</p>' + '<p class="rating">' + "<b>Rating: </b>" + location.rating + '</p>' + '<p class="price">' + "<b>Price range: </b>" + location.price + '</p>' + '<p class="location">' + "<b>Address: </b>" + location.location + '</p>' + '<p class="phone">' + "<b>Phone: </b>" + location.phone + '</p>' + '<a href="' + location.url + '">' + 'See more on yelp' + '</a>' + '</div>'; contentsBefSort.push(htmlStr); }); sortArr(contentsBefSort); if (ready) { weatherData(function (data) { console.log(data); var city = data.name; var currWeather = data.weather[0].description; var pic = 'http://openweathermap.org/img/w/' + data.weather[0].icon + '.png'; var currTemp = data.main.temp; var tempHi = data.main.temp_max; var humid = data.main.humidity; var div = '<div class="weatherIn"></div>'; $('body').append(div); $('.weatherIn').append( '<h2>Weather for Downtown ' + city + '</h2>' + '<p>Description: ' + currWeather + '</p>' + '<img src="' + pic + '" alt="Pic here" />' + '<p>Current temperature: ' + currTemp + '&#8457' + '</p>' + '<p>The high for today is ' + tempHi + '&#8457' + '</p>' + '<p>Humidity: ' + humid + '</p>'); }); initMap(); } } }); function sortList() { $('.search').keyup(function (e) { var val = $('.search').val(); var list = $('.btns li'); if (val != "") { $(list).css("display", "none"); $(list).each(function (i) { var h2text = $(this).find('h2').text(); if (h2text.includes(val)) { $(this).css("display", "block"); } }); } else { $(list).css("display", "block"); } }); }; function sortArr(arr) { for (var j = 0; j < locations.length; j++) { for (var i = 0; i < arr.length; i++) { if (arr[i].indexOf(locations[j].name) > -1 || arr[i].indexOf(locations[j].name) == 0) { contentsNew[j] = arr[i]; } } } ready = true; }; function weatherData(callback) { var weather = 'https://api.openweathermap.org/data/2.5/weather?lat=36.168743&lon=-115.139866&units=imperial&APPID=derp'; $.ajax({ dataType: "jsonp", url: weather, success: callback }); }; var initMap = function () { $(' <input type="text" placeholder="Search here" class="search" value="" />').insertBefore('.btns'); if (ready) { var map; map = new google.maps.Map(document.getElementById('map'), { center: { lat: 36.168743, lng: -115.139866 }, zoom: 15 }); for (let i = 0; i < locations.length; i++) { //make markers markers[i] = new google.maps.Marker({ position: new google.maps.LatLng(locations[i].coords.lat, locations[i].coords.lng), map: map, title: locations[i].name }); markers[i].index = i; //add index $('.btns').append('<li>' + contentsNew[i] + '</li>'); var infoWindow = new google.maps.InfoWindow(); infoWindow.setOptions({ maxWidth: 250 }); google.maps.event.addListener(markers[i], 'click', function () { (this.index); infoWindow.setContent([contentsNew[i]].toString()); infoWindow.open(map, markers[this.index]); map.setZoom(16); map.panTo(markers[this.index].getPosition()); }); var list = $('.btns li'); //console.log(list[i]); google.maps.event.addDomListener(list[i], 'click', function () { infoWindow.setContent([contentsNew[i]].toString()); map.setZoom(16); infoWindow.open(map, markers[i]); map.panTo(markers[i].getPosition()); }); var mapCenter = new google.maps.LatLng(36.168743, -115.139866); google.maps.event.addListener(infoWindow, 'closeclick', function () { map.setCenter(mapCenter); map.setZoom(15); }); }; }; sortList(); }; return { initMap: initMap }; })(); 7 imprimirá los nodos. Debe utilizarse después de var Module = (function () { var markers = []; var contentsBefSort = []; var infoWindows = []; var contentsNew = []; var ready = false; //model data var locations = [{ name: 'Le Thai', coords: { lat: 36.168743, lng: -115.139866 } }, { name: 'Atomic Liquors', coords: { lat: 36.166782, lng: -115.13551 } }, { name: 'The Griffin', coords: { lat: 36.168785, lng: -115.140329 } }, { name: 'Pizza Rock', coords: { lat: 36.17182, lng: -115.142304 } }, { name: 'The Mob Museum', coords: { lat: 36.172815, lng: -115.141242 } }, { name: "Joe Vicari's Andiamo Italian Steakhouse", coords: { lat: 36.169437, lng: -115.142903 } }, { name: 'eat.', coords: { lat: 36.166535, lng: -115.139067 } }, { name: "Hugo's Cellar", coords: { lat: 36.169915, lng: -115.143861 } }, { name: 'Therapy', coords: { lat: 36.169041, lng: -115.139829 } }, { name: 'VegeNation', coords: { lat: 36.167401, lng: -115.139453 } } ]; //convert array to JSON var jsonStr = JSON.stringify(locations); $.ajax({ url: 'https://gentle-fortress-70127.herokuapp.com/p', type: "POST", contentType: "application/json", // <==== data: jsonStr, success: function (data) { $.each(data, function (i, location) { var htmlStr = ""; var hours = ""; console.log(location.hours); if (location.hours == false) { hours = "Is closed"; } else { hours = "Is open"; } htmlStr += '<div class ="info">' + '<h2 class="name">' + location.name.toString() + '</h2>' + '<img class="buspic" src=' + location.img + " alt text='bus pic'" + '/>' + '<p class="hours">' + "<b>Open or closed: </b>" + hours + '</p>' + '<p class="reviews">' + "<b>Review count: </b>" + location.revcount + '</p>' + '<p class="rating">' + "<b>Rating: </b>" + location.rating + '</p>' + '<p class="price">' + "<b>Price range: </b>" + location.price + '</p>' + '<p class="location">' + "<b>Address: </b>" + location.location + '</p>' + '<p class="phone">' + "<b>Phone: </b>" + location.phone + '</p>' + '<a href="' + location.url + '">' + 'See more on yelp' + '</a>' + '</div>'; contentsBefSort.push(htmlStr); }); sortArr(contentsBefSort); if (ready) { weatherData(function (data) { console.log(data); var city = data.name; var currWeather = data.weather[0].description; var pic = 'http://openweathermap.org/img/w/' + data.weather[0].icon + '.png'; var currTemp = data.main.temp; var tempHi = data.main.temp_max; var humid = data.main.humidity; var div = '<div class="weatherIn"></div>'; $('body').append(div); $('.weatherIn').append( '<h2>Weather for Downtown ' + city + '</h2>' + '<p>Description: ' + currWeather + '</p>' + '<img src="' + pic + '" alt="Pic here" />' + '<p>Current temperature: ' + currTemp + '&#8457' + '</p>' + '<p>The high for today is ' + tempHi + '&#8457' + '</p>' + '<p>Humidity: ' + humid + '</p>'); }); initMap(); } } }); function sortList() { $('.search').keyup(function (e) { var val = $('.search').val(); var list = $('.btns li'); if (val != "") { $(list).css("display", "none"); $(list).each(function (i) { var h2text = $(this).find('h2').text(); if (h2text.includes(val)) { $(this).css("display", "block"); } }); } else { $(list).css("display", "block"); } }); }; function sortArr(arr) { for (var j = 0; j < locations.length; j++) { for (var i = 0; i < arr.length; i++) { if (arr[i].indexOf(locations[j].name) > -1 || arr[i].indexOf(locations[j].name) == 0) { contentsNew[j] = arr[i]; } } } ready = true; }; function weatherData(callback) { var weather = 'https://api.openweathermap.org/data/2.5/weather?lat=36.168743&lon=-115.139866&units=imperial&APPID=derp'; $.ajax({ dataType: "jsonp", url: weather, success: callback }); }; var initMap = function () { $(' <input type="text" placeholder="Search here" class="search" value="" />').insertBefore('.btns'); if (ready) { var map; map = new google.maps.Map(document.getElementById('map'), { center: { lat: 36.168743, lng: -115.139866 }, zoom: 15 }); for (let i = 0; i < locations.length; i++) { //make markers markers[i] = new google.maps.Marker({ position: new google.maps.LatLng(locations[i].coords.lat, locations[i].coords.lng), map: map, title: locations[i].name }); markers[i].index = i; //add index $('.btns').append('<li>' + contentsNew[i] + '</li>'); var infoWindow = new google.maps.InfoWindow(); infoWindow.setOptions({ maxWidth: 250 }); google.maps.event.addListener(markers[i], 'click', function () { (this.index); infoWindow.setContent([contentsNew[i]].toString()); infoWindow.open(map, markers[this.index]); map.setZoom(16); map.panTo(markers[this.index].getPosition()); }); var list = $('.btns li'); //console.log(list[i]); google.maps.event.addDomListener(list[i], 'click', function () { infoWindow.setContent([contentsNew[i]].toString()); map.setZoom(16); infoWindow.open(map, markers[i]); map.panTo(markers[i].getPosition()); }); var mapCenter = new google.maps.LatLng(36.168743, -115.139866); google.maps.event.addListener(infoWindow, 'closeclick', function () { map.setCenter(mapCenter); map.setZoom(15); }); }; }; sortList(); }; return { initMap: initMap }; })(); 8 o, de lo contrario, resultará en un mensaje de error.

No estoy buscando ninguna entrada, estilo, comentarios, funciones usadas, cualquier cosa.

  var Module = (function () {      var markers = [];     var contentsBefSort = [];     var infoWindows = [];     var contentsNew = [];     var ready = false;      //model data     var locations = [{             name: 'Le Thai',             coords: {                 lat: 36.168743,                 lng: -115.139866             }         }, {             name: 'Atomic Liquors',             coords: {                 lat: 36.166782,                 lng: -115.13551             }         }, {             name: 'The Griffin',             coords: {                 lat: 36.168785,                 lng: -115.140329             }         }, {             name: 'Pizza Rock',             coords: {                 lat: 36.17182,                 lng: -115.142304             }         }, {             name: 'The Mob Museum',             coords: {                 lat: 36.172815,                 lng: -115.141242             }         }, {             name: "Joe Vicari's Andiamo Italian Steakhouse",             coords: {                 lat: 36.169437,                 lng: -115.142903             }         }, {             name: 'eat.',             coords: {                 lat: 36.166535,                 lng: -115.139067             }         }, {             name: "Hugo's Cellar",             coords: {                 lat: 36.169915,                 lng: -115.143861             }         }, {             name: 'Therapy',             coords: {                 lat: 36.169041,                 lng: -115.139829             }         }, {             name: 'VegeNation',             coords: {                 lat: 36.167401,                 lng: -115.139453             }         }      ];        //convert array to JSON     var jsonStr = JSON.stringify(locations);      $.ajax({         url: 'https://gentle-fortress-70127.herokuapp.com/p',         type: "POST",         contentType: "application/json", // <====         data: jsonStr,         success: function (data) {             $.each(data, function (i, location) {                 var htmlStr = "";                 var hours = "";                 console.log(location.hours);                 if (location.hours == false) {                     hours = "Is closed";                 } else {                     hours = "Is open";                 }                  htmlStr += '<div class ="info">' +                 '<h2 class="name">' + location.name.toString() + '</h2>' +                 '<img class="buspic" src=' + location.img + " alt text='bus pic'" + '/>' +                 '<p class="hours">' + "<b>Open or closed: </b>" + hours + '</p>' +                 '<p class="reviews">' + "<b>Review count: </b>" + location.revcount + '</p>' +                 '<p class="rating">' + "<b>Rating: </b>" + location.rating + '</p>' +                 '<p class="price">' + "<b>Price range: </b>" + location.price + '</p>' +                 '<p class="location">' + "<b>Address: </b>" + location.location + '</p>' +                 '<p class="phone">' + "<b>Phone: </b>" + location.phone + '</p>' +                 '<a href="' + location.url + '">' + 'See more on yelp' + '</a>' +                 '</div>';                  contentsBefSort.push(htmlStr);              });              sortArr(contentsBefSort);                if (ready) {                 weatherData(function (data) {                     console.log(data);                     var city = data.name;                     var currWeather = data.weather[0].description;                     var pic = 'http://openweathermap.org/img/w/' + data.weather[0].icon + '.png';                     var currTemp = data.main.temp;                     var tempHi = data.main.temp_max;                     var humid = data.main.humidity;                      var div = '<div class="weatherIn"></div>';                     $('body').append(div);                      $('.weatherIn').append(                         '<h2>Weather for Downtown ' + city + '</h2>' +                         '<p>Description: ' + currWeather + '</p>' +                         '<img src="' + pic + '" alt="Pic here" />' +                         '<p>Current temperature: ' + currTemp + '&#8457' + '</p>' +                         '<p>The high for today is ' + tempHi + '&#8457' + '</p>' +                         '<p>Humidity: ' + humid + '</p>');                  });                 initMap();              }         }     });     function sortList() {          $('.search').keyup(function (e) {             var val = $('.search').val();             var list = $('.btns li');             if (val != "") {                 $(list).css("display", "none");                 $(list).each(function (i) {                     var h2text = $(this).find('h2').text();                      if (h2text.includes(val)) {                          $(this).css("display", "block");                      }                 });             } else {                 $(list).css("display", "block");             }          });      };      function sortArr(arr) {          for (var j = 0; j < locations.length; j++) {              for (var i = 0; i < arr.length; i++) {                  if (arr[i].indexOf(locations[j].name) > -1 || arr[i].indexOf(locations[j].name) == 0) {                        contentsNew[j] = arr[i];                    }             }         }          ready = true;     };      function weatherData(callback) {         var weather = 'https://api.openweathermap.org/data/2.5/weather?lat=36.168743&lon=-115.139866&units=imperial&APPID=derp';          $.ajax({             dataType: "jsonp",             url: weather,             success: callback         });     };      var initMap = function () {          $(' <input type="text" placeholder="Search here" class="search" value="" />').insertBefore('.btns');          if (ready) {             var map;             map = new google.maps.Map(document.getElementById('map'), {                     center: {                         lat: 36.168743,                         lng: -115.139866                     },                     zoom: 15                 });              for (let i = 0; i < locations.length; i++) {                  //make markers                 markers[i] = new google.maps.Marker({                         position: new google.maps.LatLng(locations[i].coords.lat, locations[i].coords.lng),                         map: map,                         title: locations[i].name                     });                  markers[i].index = i; //add index                  $('.btns').append('<li>' + contentsNew[i] + '</li>');                   var infoWindow = new google.maps.InfoWindow();                  infoWindow.setOptions({                     maxWidth: 250                 });                  google.maps.event.addListener(markers[i], 'click', function () {                     (this.index);                     infoWindow.setContent([contentsNew[i]].toString());                     infoWindow.open(map, markers[this.index]);                     map.setZoom(16);                     map.panTo(markers[this.index].getPosition());                 });                 var list = $('.btns li');                 //console.log(list[i]);                 google.maps.event.addDomListener(list[i], 'click', function () {                     infoWindow.setContent([contentsNew[i]].toString());                     map.setZoom(16);                     infoWindow.open(map, markers[i]);                     map.panTo(markers[i].getPosition());                 });                  var mapCenter = new google.maps.LatLng(36.168743, -115.139866);                  google.maps.event.addListener(infoWindow, 'closeclick', function () {                     map.setCenter(mapCenter);                     map.setZoom(15);                 });             };         };          sortList();      };      return {         initMap: initMap     }; })(); 9  

Quiero agregar más opciones, ordenar, buscar, eliminar y abrir la integración de archivos, pero me gustaría asegurarme de que esto funcione correctamente primero.

Original en ingles

This program will create a linked list, set the values, and print the list by using command line options.

This is my first implementation of a linked list so I'm not sure if I did it correctly. The available options are:

-a to add nodes.

To add several nodes:-a "23 56 1" will add three nodes with the respective values

-p will print the nodes. It has to be used after -a or else it will result in an error message.

I'm not looking for any specific input, style, comments, functions used, anything.

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>  struct node{     int value;     struct node *next_ptr; };  struct node *head;  void add_node(int data); void print_nodes(void);  int main(int argc, char *argv[]){     int c;     long node_value;     char *ptr;     char *token;     const char s[2] = " "; /*Split optarg based on this string*/      while((c = getopt(argc, argv, "pa:")) != EOF){         switch(c){         case 'p':             print_nodes();             break;         case 'a':             token = strtok(optarg, s); /*Split the string*/             while(token != NULL){                 node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/                 if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid input*/                     fprintf(stderr, "Invalid number: %c", *ptr);                     exit(EXIT_FAILURE);                 }                 add_node(node_value);                 token = strtok(NULL, s);             }             break;         default:             fprintf(stderr, "Unknown option %c, available options are '-p' and 'a'", c);             break;         }     }     argc -= optind;     argv += optind;      return 0; }  void add_node(int data){     struct node *temp = head;      if(temp == NULL){         head = malloc(sizeof(struct node));         head->value = data;         head->next_ptr = NULL;         return;     }      while(temp->next_ptr != NULL){         temp = temp->next_ptr;     }      if((temp->next_ptr = malloc(sizeof(struct node))) == NULL){         fprintf(stderr, "Out of memory");         exit(EXIT_FAILURE);     }      temp = temp->next_ptr;     temp->value = data;     temp->next_ptr = NULL; }  void print_nodes(void){     struct node *temp = head;     if(temp == NULL){             printf("Linked list is empty\n");     }     for(temp = head; temp != NULL; temp = temp->next_ptr){         printf("%i\n", temp->value);     } } 

I want to add more options, sort, search, delete and file integration, but I'd like to make sure this is working correctly first.

        

Lista de respuestas

5
 
vote
vote
La mejor respuesta
 

Su programa cumple en gran medida el objetivo principal que se establece para lograr: Construir e imprimir listas enlazadas desde la línea de comandos. Parece que entiende la estructura de datos de la lista vinculada por individuos y algoritmos relacionados para agregar nodos y atravesar bastante bien. Dicho esto, hay varias oportunidades de mejora en su código relacionado con la implementación de la lista vinculada y para las prácticas generales de programación.

  function defaultCompare(x, y) {   if (x < y)     return -1;   else if (x > y)     return 1;   else     return 0; }  function insertionSort(array, compare) {   compare = compare ? compare : defaultCompare;   //... } 7  

function defaultCompare(x, y) { if (x < y) return -1; else if (x > y) return 1; else return 0; } function insertionSort(array, compare) { compare = compare ? compare : defaultCompare; //... } 8 es ampliamente compatible, pero no una biblioteca estándar. Considere reemplazarlo para una mayor portabilidad.

  function defaultCompare(x, y) {   if (x < y)     return -1;   else if (x > y)     return 1;   else     return 0; }  function insertionSort(array, compare) {   compare = compare ? compare : defaultCompare;   //... } 9  

Como se mencionó en @pacmaninbw, considere usar un 99887766655443330 , por lo que posteriormente puede usar solo 99887766655443331 en lugar de totalElements2 . La denominación exacta es discutible.

  totalElements3  

Intente mucho para evitar variables globales como esta. En su lugar, casi siempre es preferible pasar variables como parámetros de función. En este caso, mueva totalElements4 INTERIOR totalElements5 p>

Tenga en cuenta que para cambiar totalElements8 como una variable local de totalElements9 o totalElements41

usted Necesitará pasar un for2 en lugar de solo un for3 . La razón de esto es que los parámetros son las variables locales, por lo que si for44 fueron para establecer su parámetro 99887776655443345 Estaría cambiando su copia y no La copia mantenida por for6 . En su lugar, si el parámetro es for7 for8 puede pasar un puntero a su copia local pasando for9 y inputArray.length - 10 Puede cambiar la copia en inputArray.length - 11 por indirección: inputArray.length - 12 .

  inputArray.length - 13  

Funciones de declaración a futuro está bien y en este pequeño programa Una opción en su mayoría estilística que le permite poner inputArray.length - 14 ANTES DE inputArray.length - 15 y inputArray.length - 16 . Alternativamente, podría colocar inputArray.length - 17 dure y evite las declaraciones delanteras. Una ventaja de ese enfoque es que no tendrá que cambiar dos lugares cuando cambie la firma de estas funciones, como agregar inputArray.length - 18 como parámetro.

  inputArray.length - 19  

En general, se considera una buena práctica para declarar variables lo más cerca posible de su uso para limitar su alcance y reducir el número de variables lectores y los mantenedores deben mantenerse en sus cabezas. En este caso, solo debe declararse en este punto a declararse totalElements0655443360. El resto de las variables se puede declarar dentro del bloque totalElements655443361 LOOP o, al agregar tirantes rizados para hacer bloques dentro del totalElements2 Etiquetas.

  totalElements3  

Tenga en cuenta que si cae el totalElements4 deberá presentar una alternativa a totalElements5 . Eso debería ser bastante fácil, pero puede complicar el código ligeramente. Es posible que desee implementar literalmente su propia versión de totalElements6, pero también puede conformarse con reemplazar este bucle con un bucle sobre el 99887776655443367 matriz que lee pares de argumentos en el índice totalElements8 y totalElements9 .

  temp0  

Está bien, y en común, para romper el código en su propia función. También puede preferir la estética. Sin embargo, para la integridad, mencionaré un inconveniente. En este caso, temp1 solo se llama desde un lugar. Puede copiar su cuerpo aquí y evitar la llamada de la función. La mayoría de los compiladores de optimización hará esto por usted, por lo que esto no resultará en una ganancia de rendimiento. Lo que ayudará, posiblemente, es la legibilidad.

Los lectores de temp2 actualmente necesitan suspender su progreso a través de esta función y saltar a otra ubicación en el archivo. Deben recordar las asignaciones de los parámetros a los valores correspondientes en temp3 . Luego, cuando terminan leyendo temp4 necesitan recordar dónde estaban en temp5 y saltar a esa ubicación en el archivo. Algunos editores de texto e IDES pueden ayudar con el salto, pero hay un aumento en la carga cognitiva causada por dividir este código en otro Función y es posible que desee considerar eliminarlo hasta que tenga varias personas que llaman.

  temp6  

Como se mencionó en otras revisiones de código, hay un par de problemas aquí. Primero, es que temp7

devuelve un temp8 y le está asignando a solo un temp9 . Dependiendo de los tamaños de enteros de su plataforma, temp0 y 99887766555443381 puede no tener el mismo tamaño. Puede solucionar esto de varias maneras, pero es posible que desee considerar simplemente cambiar los valores mantenidos en la lista enlazada de temp2 a temp3 . Alternativamente, es posible que deba hacer algo de conversión y / o plantear un error si el valor dado se ajusta a temp4 pero no en el 998877766555443385 .

  temp6  

El segundo problema la falta de revisión de errores. Esta revisión de errores no cubre todos los casos de error. Si el usuario coloca en una cadena no entera, como temp7 , 99887776655443388 devolverá 99887776655443389 . Desafortunadamente, esto es difícil de detectar como un error ya que function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 0 es un valor entero válido. Si el valor está fuera de rango, puede verificar function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 1 para ver si se ha establecido en function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 2 . Este es el manejo de errores caro e incómodo, especialmente para una función tan simple. Puede considerar escribir su propia versión como la mencionada en la revisión por @pacmaninbw.

  function swapIndices(array, index1, index2) {   var temp = array[index1];   array[index1] = array[index2];   array[index2] = temp; } 3  

También como se mencionó en otras reseñas, llame a function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 4 está bien en un programa tan pequeño, pero generalmente no es una muy buena manera de manejar errores. Esto es especialmente cierto al manejar las entradas del programa que están fuera del control del Código. En su lugar, la mayoría de los programas apuntan a fallar con gracia reportando el error (que hizo), pero luego continúe. Si el error es verdaderamente fatal para el programa, como en este caso, entonces 998877766554433955 puede estar justificado.

  function swapIndices(array, index1, index2) {   var temp = array[index1];   array[index1] = array[index2];   array[index2] = temp; } 6  

Como con function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 7 Existe un solo sitio de llamada a function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 8 para que pueda considerar mover su cuerpo aquí y eliminar function swapIndices(array, index1, index2) { var temp = array[index1]; array[index1] = array[index2]; array[index2] = temp; } 9 .

  insertionSort00  

Este error se maneja (indirectamente) devolviendo insertionSort01 (éxito). En el caso de un valor de nodo no válido, se maneja el error al regresar (a través de insertionSort02 ) el valor de falla. Dado que esto es tan fatal de un error anterior, debe devolver el mismo código de error para indicar al sistema operativo que el programa ha terminado con un error, no con éxito.

  insertionSort03  

Cambiar estas variables locales es innecesario en este punto porque tampoco se usa antes de regresar.

  insertionSort04  

Como con su uso de insertionSort05 arriba, debe usar insertionSort06 aquí. Si lo hace, no requiere que el lector sepa que insertionSort07 indica el éxito, aunque ese es el conocimiento común.

  insertionSort08  

insertionSort09 nunca se inicializa por su código, por lo que su valor no estará indefinido la primera vez que se ejecute esta función. A veces, el compilador la inicializará a insertionSort10 para usted, especialmente cuando se encuentra en el modo "Depuración", por lo que es posible que no haya notado este error. Cuando el compilador no tiene no inicializado insertionSort11 para usted, es extremadamente poco probable que ocurra que sea inicialmente insertionSort12 . En ese caso, se omitirá este insertionSort13 y se accederá a la memoria (esencialmente aleatoria) a insertionSort14 . También es extremadamente extremadamente improbable que dicha memoria esté disponible para su programa, por lo que el sistema operativo ciertamente terminará su programa con un "choque". Lo mismo ocurre con otros usos de insertionSort15 , como en insertionSort16 .

  insertionSort17  

Algunos programadores fruncen el ceño sobre "Retornos tempranos" o "Retornos múltiples". Es sobre todo una elección estilística, pero uno de los que debe ser consciente. En su lugar, podría agregar un 998877666554433118 y poner el resto de la función.

  insertionSort19  

Si desea realizar un seguimiento de la "cola" o "FIN" de la lista, como lo hace con insertionSort20 puede saltar este bucle. En realidad, es un bucle extremadamente caro, ya que se leerá continuamente de la memoria dispersada a través de RA . Es muy probable que cada iteración de este bucle cause una falla de CPU Cache y se deba purgar todo el caché para que se rellene con la memoria en la ubicación del siguiente nodo. Mantener un puntero de "cola" requerirá un uso adicional (4 u 8 bytes) de memoria adicional, pero su código se ejecutará mucho más rápidamente.

  insertionSort21  

Comprobación de un insertionSort22

Retorno de insertionSort23 es una buena idea, pero en este caso es posiblemente innecesario. Si está asignando un gigabyte, entonces es posible que la asignación falle. Si está asignando un insertionSort24 (aproximadamente 8-16 bytes) y el sistema operativo no puede devolver esa cantidad de memoria, es probable que la computadora se bloquee de todos modos. Probablemente no podrá imprimir el error, ya que el sistema no se queda básicamente. Por lo tanto, en este caso, es probable que sea mejor omitir el cheque por el bien de la cantidad reducida de código, lo que significa que hay menos de tipo, menos de leer, y el ejecutable es más pequeño.

  insertionSort25  

Esta es una implementación de "libro de texto" de una lista vinculada individualmente en su forma más sencilla. Sin embargo, si quisiste ir más allá, existe una optimización que aumentaría enormemente su rendimiento y su eficiencia de utilización de la memoria. Como mencioné en el comentario sobre cómo atravesar la lista es extremadamente lenta, esto se debe en gran medida a cada nodo que existe en esencialmente una ubicación aleatoria en la memoria. La ubicación exacta está más allá de su control ya que insertionSort26 hace de esta decisión. Además, es probable que insertionSort27 asigne un "bloque" de memoria mucho más grande que los bytes de 8-16 que solicitó, lo que disminuye la eficiencia de la utilización de la memoria. También está haciendo una llamada a insertionSort28 por nodo, que es bastante lento en sí mismo como insertionSort29 es bastante lento y resultará en más de más fallas en caché.

Para combatir estos problemas, puede cambiar cómo asignó los nodos de la lista vinculada. Actualmente, lo está asignando uno por uno a medida que analiza los argumentos de la línea de comandos. En su lugar, podría contar el número de argumentos de línea de comandos y asignar una matriz de ese número de nodos. Esto sería trivial si también ajusta el formato de los parámetros de la línea de comandos para que los valores del nodo se pasen individualmente en lugar de como una cadena única que la contiene todos.

Una vez que haya asignado esta matriz de nodos, debe ser una simple cuestión de asignar el 99887766555544333130 9988776655554433131 debe configurarse en insertionSort32 .

La ventaja de este esquema es que todos los nodos se almacenarán secuencialmente en la memoria. Cuando accede a la primera, la CPU almacenará en caché los siguientes nodos en mucho Memoria más rápida como L1 o L2 Cache. A medida que atravese la lista, accederá a ese caché en lugar de recuperarse de la memoria principal del sistema, que generalmente es un orden de magnitud más lento.

Esto es, por supuesto, una optimización opcional que complicará ligeramente su código al igual que mantener un puntero 9988777665554433133. Hay concesiones en complejidad, memoria y desempeño a considerar como mencioné anteriormente y depende de usted perder estas preocupaciones. En general, un buen trabajo en este programa y espero que esta revisión del código fue útil!

 

Your program largely accomplishes the core goal you set out to achieve: build and print linked lists from the command line. You seem to understand the singly-linked list data structure and related algorithms for adding nodes and traversing quite well. That said, there are several opportunities for improvement in your code related to the linked list implementation itself and for general programming practices.

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> 

unitstd.h is widely supported, but not a standard library. Consider replacing it for increased portability.

struct node{     int value;     struct node *next_ptr; }; 

As @pacmaninbw mentioned, consider using a typedef here so you can later use just node instead of struct node. Exact naming is debatable.

struct node *head; 

Try very hard to avoid global variables like this. Instead, it's almost always preferable to pass variables as function parameters. In this case, move head inside main and pass it as a new parameter to add_node and print_nodes.

Note that in order to change head as a local variable of main from either add_node or print_nodes you'll need to pass a struct node** instead of just a struct node. The reason for this is that parameters are local variables, so if add_node were to set its head parameter it would only be changing its copy and not the copy held by main. Instead, if the parameter is struct node** then main can pass a pointer to its local copy by passing &head and add_node can change the copy in main by indirection: *head = X.

void add_node(int data); void print_nodes(void); 

Forward-declaring functions is fine and in this small program a mostly stylistic choice that allows you to put main before add_node and print_nodes. Alternatively, you could put main last and avoid the forward declarations. One advantage of that approach is that you won't need to change two places when you change the signature of these functions, such as adding head as a parameter.

int main(int argc, char *argv[]){     int c;     long node_value;     char *ptr;     char *token;     const char s[2] = " "; /*Split optarg based on this string*/ 

It's generally considered good practice to declare variables as close to their usage as possible to limit their scope and reduce the number of variables readers and maintainers need to keep in their heads. In this case, only c needs to be declared at this point. The rest of the variables can be declared within the while loop's block or, by adding curly braces to make blocks inside the case labels.

    while((c = getopt(argc, argv, "pa:")) != EOF){ 

Note that if you drop the #include <unistd.h> you'll need to come up with an alternative to getopt. That should be pretty easy, but may complicate the code slightly. You may want to literally implement your own version of getopt but you may also settle for replacing this loop with a loop over the argv array that reads pairs of arguments at index i and i+1.

        switch(c){         case 'p':             print_nodes(); 

It's fine, and commonplace, to break out code into its own function. You may also prefer the aesthetics of it. However, for completeness, I'll mention one drawback. In this case print_nodes is only ever called from one place. You could copy its body here and avoid the function call. Most optimizing compilers will do this for you, so this won't result in a performance gain. What it will help, arguably, is readability.

Readers of main currently need to suspend their progress through this function and jump to another location in the file. They need to remember mappings of parameters to the corresponding values in main. Then when they're done reading print_nodes they need to remember where they were in main and jump back to that location in the file. Some text editors and IDEs can help with the jumping, but there is an increase in cognitive load that's caused by splitting out this code into another function and you might want to consider removing it until such time as you have multiple callers.

            break;         case 'a':             token = strtok(optarg, s); /*Split the string*/             while(token != NULL){                 node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/ 

As mentioned in some other code reviews, there are a couple of issues here. First is that strtol returns a long int and you're assigning it to just an int. Depending on the integer sizes of your platform, long int and int may not have the same size. You can fix this in several ways, but you may want to consider simply changing the values held in the linked list from int to long int. Alternatively, you may need to do some conversion and/or raise an error if the given value fits in long int but not in the sometimes-smaller int.

                if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid input*/ 

The second issue the lack of error checking. This error checking doesn't cover all of the error cases. If the user puts in a non-integer string such as foo then strtol will return 0. This is unfortunately difficult to detect as an error as 0 is a valid integer value. If the value is out of range, you can check errno to see if it's been set to ERANGE. This is expensive and awkward error handling, especially for such a simple function. You might consider writing your own version such as the one mentioned in the review by @pacmaninbw.

                    fprintf(stderr, "Invalid number: %c", *ptr);                     exit(EXIT_FAILURE); 

Also as mentioned in other reviews, calling exit is fine in such a small program but generally not a very good way to handle errors. This is especially true when handling program inputs that are outside of the code's control. Instead, most programs aim to gracefully fail by reporting the error (which you did) but then continue on. If the error is truly fatal to the program, as in this case, then exit may be warranted.

                }                 add_node(node_value); 

As with print_nodes there is only one call site to add_node so you could consider moving its body here and removing add_node.

                token = strtok(NULL, s);             }             break;         default:             fprintf(stderr, "Unknown option %c, available options are '-p' and 'a'", c);             break; 

This error is handled by (indirectly) returning 0 (success). In the case of an invalid node value the error is handled by returning (via exit) the failure value. Since this is just as fatal of an error as above, you should return the same error code to indicate to the OS that the program has terminated with an error, not successfully.

        }     }     argc -= optind;     argv += optind; 

Changing these local variables is unnecessary at this point because neither is used before returning.

    return 0; 

Like with your use of EXIT_FAILURE above, you should use EXIT_SUCCESS here. Doing so doesn't require the reader to know that 0 indicates success, even though that is common knowledge.

}  void add_node(int data){     struct node *temp = head;      if(temp == NULL){ 

head is never initialized by your code, so its value will be undefined the first time this function runs. Sometimes the compiler will initialize it to NULL for you, especially when building in "debug" mode so you may not have noticed this bug yet. When the compiler has not initialized head for you then it's exceedingly unlikely that it will happen to initially be NULL. In that case this if will be skipped and the (essentially random) memory pointed to by head will be accessed. It's also exceedingly unlikely that such memory will be available to your program, so the OS will almost certainly terminate your program with a "crash". The same goes for other uses of head, such as in print_nodes.

        head = malloc(sizeof(struct node));         head->value = data;         head->next_ptr = NULL;         return; 

Some programmers frown on "early returns" or "multiple returns". It's mostly a stylistic choice, but one you should be aware of. Instead, you could add an else and put the rest of the function in it.

    }      while(temp->next_ptr != NULL){         temp = temp->next_ptr;     } 

If you were to keep track of the "tail" or "end" of the list, as you do with head then you could skip this loop. It's actually an extremely expensive loop as it will continually read from memory scattered all through RAM. It's highly likely that every iteration of this loop will cause a CPU cache miss and the entire cache will need to be purged in order to be refilled with the memory at the next node's location. Keeping a "tail" pointer will require a tiny (4 or 8 byte) additional usage of memory but your code will execute much more quickly.

    if((temp->next_ptr = malloc(sizeof(struct node))) == NULL){         fprintf(stderr, "Out of memory");         exit(EXIT_FAILURE);     } 

Checking for a NULL return from malloc is usually a good idea, but in this case it is arguably unnecessary. If you're allocating a gigabyte then it's possible that the allocation will fail. If you're allocating one struct node (approximately 8-16 bytes) and the OS is unable to return that amount of memory then the computer is likely going to crash anyhow. You probably won't be able to even print the error as the system has basically no memory left. So in this case it's probably better to skip the check for the sake of reduced amount of code which means there's less to type, less to read, and the executable is smaller.

    temp = temp->next_ptr;     temp->value = data;     temp->next_ptr = NULL; }  void print_nodes(void){     struct node *temp = head;     if(temp == NULL){             printf("Linked list is empty\n");     }     for(temp = head; temp != NULL; temp = temp->next_ptr){         printf("%i\n", temp->value);     } } 

This is a "textbook" implementation of a singly-linked list in its simplest form. If, however, you wanted to go further there is an optimization that would greatly increase its performance and memory utilization efficiency. As I mentioned in the comment about traversing the list being extremely slow, this is largely due to each node existing in essentially a random location in memory. The exact location is beyond your control as malloc makes this decision. Also, malloc is likely to allocate a "block" of memory much larger than the 8-16 bytes you requested, which decreases your memory utilization efficiency. You're also making one call to malloc per node, which is quite slow in itself as malloc is quite slow and will result in even more cache misses.

To combat these problems, you could change how you allocate the nodes of the linked list. Currently you're allocating them one-by-one as you parse the command line arguments. Instead, you could count the number of command line arguments and allocate an array of that many nodes. This would be trivial if you also adjust the format of the command line parameters so that the node values are passed individually rather than as a single string containing all of them.

Once you have allocated this array of nodes it should be a simple matter of assigning each node's next_ptr to the address of the next node in the array and the value to whatever you parsed from the corresponding command line argument. Of course the last node's next_ptr should be set to NULL.

The advantage of this scheme is that all of the nodes will be stored sequentially in memory. When you access the first one, the CPU will cache the next several nodes in much faster memory such as L1 or L2 cache. As you traverse the list, you'll be accessing that cache instead of fetching from main system memory which is usually an order of magnitude slower.

This is, of course, an optional optimization that will slightly complicate your code just like keeping a tail pointer around. There are tradeoffs in complexity, memory, and performance to consider as I mentioned above and it's up to you to weight these concerns. Overall, good job on this program and I hope this code review was helpful!

 
 
 
 
6
 
vote

Número de formato, buenas variables y nombres de funciones. Aprendí más sobre getopt() del programa (solía tener que escribir mis propios parsers de línea de comandos)! Buen uso de macros del sistema como Exit_Failure.

usando typedef

Si el código usó Typedef para la definición de nodo, el código puede ser un poco más corto y más legible:

  typedef struct node{     int value;     struct node *next_ptr; } Node;  Node *head;  void add_node(int data){     Node* temp = head;      /* ... */ }  void print_nodes(void){     Node* temp = head;      /* ... */ }   

Al usar typedef se crea un nuevo tipo. Esto también podría disminuir la posibilidad de errores futuros al olvidarse de poner la estructura en algún momento. Este PackOverFlow Pregunta discute por qué podría ser Bueno para usar Typedef.

variables globales

En general, el uso de variables globales se cima. Al crear, la lectura y la depuración de las variables globales puede verse afectada por afectos secundarios y puede ser muy difícil encontrar dónde está ocurriendo el problema. Este StackOverFlow Pregunta habla sobre cuándo Es apropiado usar variables globales.

Puede ser mejor si la variable global NODE *head se declaró en main() y luego pasó por referencia a cada función que la modificó, y pasó por valor en cada función que Solo lo usé y no lo cambió.

Pasar la cabeza en cada una de las funciones haría que el siguiente cambió necesario:

          case 'p':     /*+>*/  print_nodes(head);      /* Pass by value */             break;               while(token != NULL){                 node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/                 if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid input*/                     fprintf(stderr, "Invalid number: %c", *ptr);                     exit(EXIT_FAILURE);                 }     /* ++> */   add_node(node_value, &head);        /* Pass by reference */                 token = strtok(NULL, s);             }   void add_node(int data, Node **head){     Node* temp;      if(*head == NULL){         *head = malloc(sizeof(struct node));         (*head)->value = data;         (*head)->next_ptr = NULL;         return;     }      temp = *head;     while(temp->next_ptr != NULL){         temp = temp->next_ptr;     }      if((temp->next_ptr = malloc(sizeof(struct node))) == NULL){         fprintf(stderr, "Out of memory");         exit(EXIT_FAILURE);     }      temp = temp->next_ptr;     temp->value = data;     temp->next_ptr = NULL; }  void print_nodes(Node* head){     Node* temp = head;     if(temp == NULL){         printf("Linked list is empty ");     }     for(temp = head; temp != NULL; temp = temp->next_ptr){         printf("%i ", temp->value);     } }   

Este ejemplo podría hacer que el programa sea más seguro y más fácil de depurar y leer.

conversión de tipo implícito

Mi compilador marcó la siguiente línea como una conversión de tipo implícito:

              add_node(node_value);   

Porque el Nodo_Value se declara como un largo en lugar de int,

      long node_value;  void add_node(int data) { /* ... */   

Si el Nodo_value debe ser un largo porque eso es lo que strtok() está devolviendo, puede ser mejor cambiar el tipo de entrada para add_node () o para fundir explícitamente node_value en la llamada:

              add_node((int) node_value);   

El mensaje de advertencia real que obtengo es implicit conversion loses integer precision: 'long to int' (Xcode 8.2 en El Capitan).

funciones que podrían ser útiles

Para implementar un programa de lista en línea completa Algunas funciones que podrían ser útiles son:

  typedef struct node{     int value;     struct node *next_ptr; } Node;  Node *head;  void add_node(int data){     Node* temp = head;      /* ... */ }  void print_nodes(void){     Node* temp = head;      /* ... */ } 0  

uso de la función de salida ()

El uso de la función typedef struct node{ int value; struct node *next_ptr; } Node; Node *head; void add_node(int data){ Node* temp = head; /* ... */ } void print_nodes(void){ Node* temp = head; /* ... */ } 11 puede ser problemático, en un gran sistema de software que uno está escribiendo solo una pieza, sería mejor devolver un código de error desde el typedef struct node{ int value; struct node *next_ptr; } Node; Node *head; void add_node(int data){ Node* temp = head; /* ... */ } void print_nodes(void){ Node* temp = head; /* ... */ } 2 < / Código> Función en lugar de llamarse la salida. En algunos casos, como los sistemas operativos que llaman typedef struct node{ int value; struct node *next_ptr; } Node; Node *head; void add_node(int data){ Node* temp = head; /* ... */ } void print_nodes(void){ Node* temp = head; /* ... */ } 3 puede tener Dire Consecuencias (apagado).

El lenguaje de programación de C se creó originalmente para implementar la operación Los sistemas y en algunos casos todavía se utilizan para ese propósito. Mientras que c no tiene las capacidades de lanzamiento de excepciones de C ++, Java, C # y otros errores de idiomas más modernos se pueden manejar, ya sea mediante devolución de códigos de error o usando SetJMP () y longjmp () .

 

Nice formatting, good variable and function names. I learned more about getopt() from the program (I used to have to write my own command line parsers)! Good use of system macros such as EXIT_FAILURE.

Using Typedef

If the code used typedef for the definition of node, the code might be slightly shorter and more readable:

typedef struct node{     int value;     struct node *next_ptr; } Node;  Node *head;  void add_node(int data){     Node* temp = head;      /* ... */ }  void print_nodes(void){     Node* temp = head;      /* ... */ } 

By using typedef a new type is created. This also might decrease the possibility of future errors by forgetting to put the struct in at some point. This stackoverflow question discusses why it might be good to use typedef.

Global Variables

Generally the use of global variables are frowned upon. When creating, reading and debugging code global variables can be affected by side affects and it can be very difficult to find where the problem is actually occurring. This stackoverflow question talks about when it is proper to use global variables.

It might be better if the global variable NODE *head was declared in main() and then passed by reference into each function that modified it, and passed by value into each function that only used it and didn't change it.

Passing head into each of the functions would make the following changed necessary:

        case 'p':     /*+>*/  print_nodes(head);      /* Pass by value */             break;               while(token != NULL){                 node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/                 if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid input*/                     fprintf(stderr, "Invalid number: %c", *ptr);                     exit(EXIT_FAILURE);                 }     /* ++> */   add_node(node_value, &head);        /* Pass by reference */                 token = strtok(NULL, s);             }   void add_node(int data, Node **head){     Node* temp;      if(*head == NULL){         *head = malloc(sizeof(struct node));         (*head)->value = data;         (*head)->next_ptr = NULL;         return;     }      temp = *head;     while(temp->next_ptr != NULL){         temp = temp->next_ptr;     }      if((temp->next_ptr = malloc(sizeof(struct node))) == NULL){         fprintf(stderr, "Out of memory");         exit(EXIT_FAILURE);     }      temp = temp->next_ptr;     temp->value = data;     temp->next_ptr = NULL; }  void print_nodes(Node* head){     Node* temp = head;     if(temp == NULL){         printf("Linked list is empty\n");     }     for(temp = head; temp != NULL; temp = temp->next_ptr){         printf("%i\n", temp->value);     } } 

This example might make the program safer and easier to debug and read.

Implicit Type Conversion

My compiler flagged the following line as an implicit type conversion:

            add_node(node_value); 

because node_value is declared as a long rather than int,

    long node_value;  void add_node(int data) { /* ... */ 

If node_value needs to be a long because that's what strtok() is returning, it might be better to either change the input type for add_node() or to explicitly cast node_value in the call:

            add_node((int) node_value); 

The actual warning message I get is implicit conversion loses integer precision: 'long to int' (Xcode 8.2 on El Capitan).

Functions that might be helpful

To implement a full linked list program some functions that might be helpful are:

NodePointer new_node(int value); NodePointer delete_node_by_value(int value, NodePointer head); NodePointer delete_node_by_pointer(NodePointer delete_target, NodePointer head); NodePointer find_node(int value, NodePointer head); void print_node(int value, NodePointer head);       // called by print_nodes 

Use of the exit() Function

The use of the exit() function can be problematic, in a large software system that one is writing only a piece of, it would be better to return an error code from the add_node() function rather than call exit. In some cases such as operating systems calling exit() can have dire consequences (shut down).

The C programming language was originally created to implement operating systems and in some cases is still used for that purpose. While C doesn't have the exception throwing capabilities of C++, Java, C# and other more modern languages errors can be handled, either by returning error codes or using setjmp() and longjmp().

 
 
         
         
2
 
vote

Solo un poco para agregar más allá de @pacmaninbw respuesta:

  1. mejor para escribir código que llega al punto y evite los números mágicos. Entonces el comentario se vuelve innecesario. Una nueva línea no se especifica para ser 10.

      // if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid ...  if(*ptr != ' ' && *ptr != '') {    
  2. Nota: CÓDIGO Falta de error robusto Detección / manejo en "Cadena a long a 9988777665544332 " Conversión. Podría usarlo propio strtoi() o este o enrolle su propia conversión como a continuación:

      // return true if error bool parse_int(const char *token, int *value_int) {   char *endptr;   errno = 0;   long value_long = strtol(token, &endptr, /* base */ 10);   if (token == endptr) { // no conversion     *value_int = 0;     return true;    }    #if INT_MAX < LONG_MAX   if (value_long > INT_MAX) {     *value_int = INT_MAX;     errno = ERANGE;     return true;   }   #endif   #if INT_MIN > LONG_MIN   if (value_long < INT_MIN) {     *value_int = INT_MIN;     errno = ERANGE;     return true;   }   #endif     *value_int = (int) value_long;   if (errno) {     return true; // outside long range or other ID error   }   if (*endptr != ' ' && *endptr != '') { // junk at the end     return true;    }   return false; }   
  3. Al mantener a las variables locales a donde se necesitan, en lugar de declararlas muy arriba, es más fácil de revisar.

      // long node_value; .... 12 lines     while(token != NULL){         long node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/         ...            add_node(node_value);   

[editar]

  1. Considere los siguientes estilos de asignación. Con el estilo de OP, sizeof(struct node) , es mejor validado como el tamaño correcto marcando el 9988777665544337 Declaración algunas 50 líneas arriba. Si se debe head8 Cambio, a través del mantenimiento, existe la obligación de cambiar las líneas del código 50 a continuación. El estilo alternativo no tiene ninguno de esos cortos. Es más fácil de código correctamente, revisa y mantiene.

      // OP's head = malloc(sizeof(struct node));  // Alternate head = malloc(sizeof *head);   
 

Only a bit to add beyond @pacmaninbw answer:

  1. Better to write code that gets to the point and avoid magic numbers. Then the comment becomes unnecessary. A new-line is not specified to be 10.

    // if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid ...  if(*ptr != '\n' && *ptr != '\0') { 
  2. Note: Code lacks robust error detection/handling in "string to long to int" conversion. Could use you own strtoi() or this or roll your own conversion like below:

    // return true if error bool parse_int(const char *token, int *value_int) {   char *endptr;   errno = 0;   long value_long = strtol(token, &endptr, /* base */ 10);   if (token == endptr) { // no conversion     *value_int = 0;     return true;    }    #if INT_MAX < LONG_MAX   if (value_long > INT_MAX) {     *value_int = INT_MAX;     errno = ERANGE;     return true;   }   #endif   #if INT_MIN > LONG_MIN   if (value_long < INT_MIN) {     *value_int = INT_MIN;     errno = ERANGE;     return true;   }   #endif     *value_int = (int) value_long;   if (errno) {     return true; // outside long range or other ID error   }   if (*endptr != '\n' && *endptr != '\0') { // junk at the end     return true;    }   return false; } 
  3. By keeping variables local to where they are needed, rather than declaring them far above, it is easier to review.

    // long node_value; .... 12 lines     while(token != NULL){         long node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/         ...            add_node(node_value); 

[Edit]

  1. Consider the following allocation styles. With OP's style, sizeof(struct node), is best validated as the right size by checking the head declaration some 50 lines above. Should head type change, through maintenance, there is an obligation to change code 50 lines below. The alternate style has neither of those short-comings. It is easier to code correctly, review and maintain.

    // OP's head = malloc(sizeof(struct node));  // Alternate head = malloc(sizeof *head); 
 
 

Relacionados problema

12  Impresión similar a la consola del mensaje JavaScript  ( Console like printing of message javascript ) 
Estoy aprendiendo a Javascript y he hecho un pequeño script de modificación de documentos muy simple que imprime un mensaje como si fuera alguien escribiendo ...

2  Connect4 con AI  ( Connect4 with ai ) 
He hecho una aplicación connect 4 consola en C ++ y amaría algunos comentarios. En este proyecto he aprendido sobre la herencia y el uso de funciones virtuale...

15  Juego de blackjack basado en texto  ( Text based blackjack game ) 
Soy un nuevo programador (he estado haciendo Java durante aproximadamente 7 semanas) y soy del tipo que quiera conseguirlo directamente, así que me pregunto c...

6  PRIGO DE PODER TICTACTOO EN C #  ( Command prompt tictactoe in c ) 
Escribí un juego básico de comando TIC TAC TOE juego. Quiero saber qué se puede mejorar en términos de modelado y qué errores he hecho (si corresponde). vo...

7  Conductor VGA simple para un kernel de juguete  ( Simple vga driver for a toy kernel ) 
Aprendo sobre el desarrollo del sistema operativo y siga el tutorial huesos desnudos en Osdev. Y hice algunas tareas adicionales de la sección avanzada. M...

13  "¡Hola Mundo!" Programa utilizando una clase para imprimir  ( Hello world program using a class for printing ) 
Eche un vistazo a mi programa y déjeme saber cómo puedo mejorarlo. /* " To Print A Line On The Display Screen" Date:5th January 2011 Programmer:F...

0  Herramienta de línea de comandos para extraer, buscar y convertir  ( Command line tool for extracting searching and converting ) 
Acabo de completar mi primera aplicación real (aplicación de línea de comandos). Es simple, pero no tenía conocimiento previo de Python. Todo fue golpeado y f...

3  Programa de Console ATM  ( Atm console program ) 
Decidí escribir un programa de cajero automático en mi idioma de programación favorito, C #. Probado con algunos números y estoy seguro de que le dará una s...

5  Colector de archivos M3U  ( M3u file collector ) 
Soy nuevo en Python y escribió este código para recopilar todos los archivos en un archivo M3U (Lista de reproducción) y copiándolos en un directorio. impo...

4  Descarga un git repo sin .git carpeta  ( Download a git repo without git folder ) 
Viniendo de Python, JavaScript y PHP, me gustaría aprender a escribir Ruby en la forma en que se "supone". El código de Python bien escrito se llama "Pythonic...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos