Thread: Help with strcpy() in multidimensional linked list

  1. #1
    Registered User
    Join Date
    May 2009
    Posts
    7

    Help with strcpy() in multidimensional linked list

    Hi, I'm new to C programming and in my assignments I'm required to create a multidimensional linked list. When I was compiling, one of the nodes' data gave me a problem of:
    passing argument 1 and 2 of 'strcpy()' makes pointer from integer without a cast. I was wondering if you all could help me take a look at what's wrong with it?

    Uhm this is the header file:
    Code:
    typedef struct price
    {
       unsigned dollars;
       unsigned cents;
    } PriceType;
    
    typedef struct item
    {
       char itemID[ID_LEN + 1];
       char itemName[MAX_NAME_LEN + 1];
       PriceType prices[NUM_PRICES];
       char itemDescription[MAX_DESC_LEN];
       ItemTypePtr nextItem;
    } ItemType;
    
    typedef struct category
    {
       char categoryID[ID_LEN + 1];
       char categoryName[MAX_NAME_LEN + 1];
       char fareType[MIN_DESC_LEN];      /* (F)ull or (C)oncession */
       char categoryDescription[MAX_DESC_LEN];
       struct category *nextCategory;
       ItemTypePtr headItem;
       unsigned numItems;
    } CategoryType;
    
    typedef struct fms
    {
       CategoryTypePtr headCategory;
       unsigned numCategories;
    } FMSType;
    and this is the part in the function that has problems:
    Code:
    int loadData(FMSType* fms, char* fareFile, char* subfareFile)
    {
    	CategoryTypePtr currCat, prevCat = NULL, newCat;
    	ItemTypePtr currIt, prevItem = NULL, newItem;
            FILE *fp1, *fp2;
    	char *ptr;
    	char line[MAX_DESC_LEN];
    	char temp1[MAX_DESC_LEN];
    	char temp2[MAX_DESC_LEN];
    	char temp3[MAX_DESC_LEN];
    	char temp4[MAX_DESC_LEN];
    	char check[MAX_DESC_LEN];
    	char dollars[MAX_DESC_LEN], cents[MAX_DESC_LEN];
    	int dollarVar, centsVar;
    
            /*code of the first linked list*/
    
            fp2 = fopen(subfareFile, "r");
            if(fp2 == NULL){
    	        printf("Unable to open file %s\n", subfareFile);
    	        exit(EXIT_SUCCESS);
            }
            else {
                    printf("\n fopen successfully opened the file %s\n\n", subfareFile);
            }
            while( fgets( line, MAX_DESC_LEN, fp2 ) != NULL){
    	
    		char* ptr = strtok(line, "|");
    		strcpy(temp1, ptr);
    		ptr = strtok(NULL, "|");
    		strcpy(check, ptr);
    		ptr = strtok(NULL, "|");
    		strcpy(temp2, ptr);
    		ptr = strtok(NULL, "|");
    		strcpy(temp3, ptr);
    		ptr = strtok(NULL, "|");
    		strcpy(temp4, ptr);
    		char *ptr1 = strtok(temp3, ".");
    		strcpy(dollars, ptr1);
    		ptr1 = strtok(NULL, ".");
    		strcpy(cents, ptr1);
    		dollarVar = atoi(dollars);
    	        centsVar = atoi(cents);
    
    	        currCat = fms->headCategory;
    		while(currCat != NULL){
                             if(strcmp(currCat->categoryID, check) == 0){
    	                         currIt = currCat->headItem;
                                     prevItem = NULL;
                                     while ( currIt != NULL){
    				           prevItem = currIt;
                                               currIt = currIt->nextItem;
                                     }
    			         if((newItem = malloc(sizeof(struct item))) == NULL){
    			                   fprintf(stderr, "Could not allocate %d bytes of memory\n", sizeof(CategoryType));
    			                   return EXIT_FAILURE;
    		                 }
    
    		                 newItem->nextItem = NULL;
                                     strcpy(newItem->itemID, temp1);
                                     strcpy(newItem->itemName, temp2);
                                     strcpy(currIt->prices[0].dollars, dollarVar);       /*<----- error here*/
    			         strcpy(currIt->prices[0].cents, centsVar);          /*<----- error here*/
                                     strcpy(newItem->itemDescription, temp4);
    
    		                  if(prevItem == NULL){
    				           currCat->headItem = newItem;
    			          }
    			          else{
    				            prevItem->nextItem = newItem;
    			          }
                                      currCat->numItems++;
                                      break;
    		          }
    		          currCat = currCat->nextCategory;
    		}
        }
    I don't quite get it how should I do this part where the PriceType prices and it's unsigned dollars and cents. How should I fix this error? Please do advice. Thanks in advance!

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    dollarVar and centsVar are both ints. strcpy() expects two pointers to char. If you're trying to turn an int into a string, you can use snprintf() (or sprintf() if you don't have snprintf(); be careful, sprintf() is dangerous).

    Unlike some scripting languages, C will not automatically turn numbers into strings. You need to do lots of things by hand that you might not expect if you're not used to C.

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    7
    Hi, thanks for the reply. If I convert dollarVar and centsVar back to string, but the data the node's pointing to is an unsigned int isn't it? Shouldn't it be in int form. Sorry, I really don't know how this should work.

    and for the snprintf() I looked up on it, a few examples
    Code:
    /* log10(num) gives the number of digits; + 1 for the null terminator */
        int size = log10(num) + 1;
        char *x = malloc(size);
        snprintf(x, size, "%d", num);
    is the malloc for x a must? just a confirmation.

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    OK, I went back and looked at (more of) your entire code, and now I'm wondering why you bothered with strcpy() at all. currIt->prices[0].dollars is an unsigned int, dollarVar is an int. Why are you not just assigning with =, as in
    Code:
    currIt->prices[0].dollars = dollarVar;
    ? As for signed/unsigned, it's not a big deal. You can verify that a string starts with a digit before converting it with atoi() (or strtoul(), which would be better); if it starts with a digit, it's not negative. Something like:
    Code:
    if(!isdigit((unsigned char)dollars[0]))
    {
      fprintf(stderr, "invalid value: %s\n", dollars);
      return -1; /* or whatever */
    }
    Unfortunately, that cast is required. One of the few times a cast is the right thing to do.

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    7
    Ah yea silly me, I tried that earlier but I forgot to change the , to = so it didn't work =\

    But after changing it to currIt->prices[0].dollars = dollarVar;
    now i got segmentation fault :S

  6. #6
    Registered User
    Join Date
    May 2009
    Posts
    7
    Uh could it be because i did not do the string verifying you just mentioned?

  7. #7
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    where is definition of ItemTypePtr and CategoryTypePtr ?

  8. #8
    Registered User
    Join Date
    May 2009
    Posts
    7
    You mean this?
    Code:
    typedef struct category* CategoryTypePtr;
    typedef struct item* ItemTypePtr;
    sorry i forgot to include it in the first post, it's with the header file on top of the structure definition

  9. #9
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    Quote Originally Posted by cas
    Unfortunately, that cast is required. One of the few times a cast is the right thing to do.
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    main()
    {
        printf("%c\n", -207);
        if (isdigit(-207))
            printf("1 yes\n");
        
        printf("%c\n", 49);
        if (isdigit(49))
            printf("2 yes\n");
        
        return 0;
    }
    Code:
    [guest@station src]$ ./test
    1
    1
    2 yes
    [guest@station src]$
    it even doesn't matter how many characters in dollars[0], function will take it as an int
    Last edited by c.user; 05-23-2009 at 03:39 AM.

  10. #10
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by c.user View Post
    it even doesn't matter how many characters in dollars[0], function will take it as an int
    By now you should know that using your particular system to "verify" whether behavior is defined is a bad idea. You obviously have a copy of the standard handy, so please consult it instead of your compiler. In this case, you would want to look at C99 7.4.1, which clearly states, regarding the ctype.h functions: "In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined."

    Therefore unless you're passing EOF, you must pass a positive value less than or equal to UCHAR_MAX. Since char can be signed, passing a char to isdigit() is not necessarily safe.

  11. #11
    Registered User
    Join Date
    May 2009
    Posts
    7
    uhm may i ask is the casting of int dollarVar and centsVar to unsigned important? is it because i did not cast it that's why i'm getting segmentation fault? if yes then how can i cast, sorry i really don't know how to cast it.

  12. #12
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Casting is usually the wrong thing to do. It is perfectly legal to assign a signed integer to an unsigned integer with no cast (and vice versa, with a small, pointless-at-this-time caveat for C99). Assigning a negative value to an unsigned type is legal, but might not be what you want, so you really should make the types match.

    It's good you don't know how to cast, because the cast is one of the things beginners abuse the most, in my experience.

  13. #13
    Registered User
    Join Date
    May 2009
    Posts
    7
    hmm then do you have any idea why segmentation fault has appeared after i changed it to
    Code:
    currIt->prices[0].dollars = dollarVar;
    currIt->prices[0].cents = centsVar;

  14. #14
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by immie86 View Post
    hmm then do you have any idea why segmentation fault has appeared after i changed it to
    Code:
    currIt->prices[0].dollars = dollarVar;
    currIt->prices[0].cents = centsVar;
    Because currIt is NULL, or otherwise invalid? This is the place for a debugger. Use valgrind if it supports your platform; otherwise try something like gdb.

  15. #15
    Registered User
    Join Date
    Apr 2009
    Location
    Russia
    Posts
    116
    Quote Originally Posted by cas
    you would want to look at C99 7.4.1
    yea, I know, but I never seen this cast in the books

    you think isdigit('0') should be incorrect ? '0' will be signed

    by the topic
    immie86, i cleared your function (don't know how it's work and suggest use sscanf instead of strtok)
    Code:
        char temp1[100], temp2[100], temp3[100];
    
        if (sscanf("one|two|three", "%99[^|]|%99[^|]|%99[^|]", temp1, temp2, temp3) != 3)
            return;
    there is no avail to attach archives (remove .txt from file)
    I wrote types which you forgot to the typedefs, and make all types in one form (It => Item)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ Linked list program need help !!!
    By dcoll025 in forum C++ Programming
    Replies: 1
    Last Post: 04-20-2009, 10:03 AM
  2. Please Help - Problem with Compilers
    By toonlover in forum C++ Programming
    Replies: 5
    Last Post: 07-23-2005, 10:03 AM
  3. How can I traverse a huffman tree
    By carrja99 in forum C++ Programming
    Replies: 3
    Last Post: 04-28-2003, 05:46 PM
  4. problem with structures and linked list
    By Gkitty in forum C Programming
    Replies: 6
    Last Post: 12-12-2002, 06:40 PM
  5. singly linked list
    By clarinetster in forum C Programming
    Replies: 2
    Last Post: 08-26-2001, 10:21 PM

Tags for this Thread