The new forums will be named Coin Return (based on the most recent vote)! You can check on the status and timeline of the transition to the new forums here.
The Guiding Principles and New Rules document is now in effect.

Help with C, character pointers and such

TwistedJesterTwistedJester Registered User regular
edited April 2008 in Help / Advice Forum
For an assignment I'm supposed to implement a crude file system in linux, and to get a better idea of how it's going to work, I'm messing around in C rather than going directly into the syscalls. I'm planning to make a linked list, where each node has the file's name, a pointer to the data (a string, basically), and a pointer to the next node (obviously). So my struct is basically
char *data;
char file[30];
struct node *next;

I decided to make the struct contain a char pointer because I don't want to just make it a huge character array as that would waste space if it was just a single word. However, I'm having a hell of a time getting the char pointer to actually work. Every time I go to print out the linked list I get a segmentation violation. Here's how I make the "files", as it is, it just takes a string (filename here) and sets both the filename and data to that string, for simplicity:
struct node *new_node;
new_node = malloc(sizeof( struct node));
char *ptr = malloc(strlen(filename));
strcpy(ptr, filename);
(*new_node).data = ptr;
strcpy((*new_node).name, filename);
printf("data = %s\n", (*new_node).data);
(*last).next = new_node;
last = new_node;
The data is set after assigning it here, but when traversing the nodes I get a segmentation violation. At first I thought it was a memory lifetime issue, but if it were, getting the filename itself would cause a seg violation, and it didn't do that until I added the code to print out the data. For further reference, here is my code to print the nodes
printf("Node #%d has name: %s and data contents: %s\n", i, (*curr_node).name, 
(*curr_node).data);

It's possible I'm just using pointers totally wrong, I haven't really used them in a long time. So... anyone have any idea what I'm doing wrong here?

TwistedJester on

Posts

  • PapillonPapillon Registered User regular
    edited April 2008
    Your code references a member "name" of struct "node", but the struct listed in your post doesn't contain an "name" member. Can you please post the complete node struct?

    Also, it looks like your second code listing is part of a function. It would be helpful if you posted the entire function so we can see what the parameters are to the function, etc.

    An unrelated aside:
    (*node).name
    
    would usually be written
    node->name
    
    . There's no difference, but the second form is easier to read.

    Papillon on
  • DrFrylockDrFrylock Registered User regular
    edited April 2008
    When you malloc the structure you don't set the next pointer of the new node to anything. This means that, while it might be NULL, it is also likely random data. Printing out the linked list by following the series of next pointers will eventually hit the uninitialized one and then you're going to dereference a pointer to a random value.

    DrFrylock on
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    Here's the entirety of my program, with the suggested edits made:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct node
    {
    	char *data;
    	char name[30];
    	struct node *next;
    };
    
    int main()
    {
    	struct node *first, *last;
    	first = malloc(sizeof(struct node));
    	last = first;
    	strcpy(first->name, "First node");
    	first->next = NULL;
    	char vartype[30];
    	
    	while(1)
    	{
    		printf("Enter the name. If you wish to quit, enter 0\n");
    		scanf("%s", vartype);
    		if (!strncmp(vartype, "0", 1))
    		{
    			printf("exiting program and printing linked list\n");
    			break;
    		}
    		else
    		{
    			struct node *new_node;
    			new_node = malloc(sizeof( struct node));
    			char *ptr = malloc(strlen(vartype));
    		        strcpy(ptr, vartype);
    			new_node->data = ptr;
    			strcpy(new_node->name, vartype);
    			printf("data = %s\n", new_node->data);
    			last->next = new_node;
    			new_node->next = NULL;
    			last = new_node;
    		}
    	}
    	struct node *curr_node;
    	curr_node = first;
    	int i = 1;
    	printf("Before printing nodes\n");
    	while(curr_node != NULL)
    	{
    		printf("Node #%d has name: %s and data contents: %s\n", i, curr_node->name, 
    curr_node->data);
    		i++;
    		curr_node = curr_node->next;
    	} 
    	return 0;
    }
    

    TwistedJester on
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    Ok, I figured it out. Didn't initialize the data variable in the first node. I feel stupid now. Thanks for the help guys.

    TwistedJester on
  • JNighthawkJNighthawk Registered User regular
    edited April 2008
    Just in case you didn't know, you're also leaking a ton of memory.

    JNighthawk on
    Game programmer
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    I'm not surprised. I haven't really done much work with memory management, but the assignment doesn't take efficiency into account, so I'm not worried.

    Out of curiosity though, do you have any suggestions regarding how to cut down on that?

    TwistedJester on
  • bremon240bremon240 Registered User regular
    edited April 2008
    Basically you want to remember that anytime you call malloc() you need to call a free() as well. So after you are done printing out your linked list, have another while loop that calls free() on each node.

    bremon240 on
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    Oh, if that's all JNighthawk was referring to, I'm going to implement a syscall to delete nodes using free. This code here was just to get the ball rolling.

    TwistedJester on
  • ASimPersonASimPerson Cold... ... and hard.Registered User regular
    edited April 2008
    A syscall? Does this assignment involve kernel programming? I realize it's not my place to question your assignment, but your program shows several other flaws that make wonder if you're actually advanced enough to be writing kernel-level code.

    If you need to see just how much memory you're leaking, there's a tool called valgrind that's standard on most Linux systems. Just do "valgrind --tool=memcheck --show_unreachable=yes your_program" (I believe that's right, at any rate) to see how bad it is. Additionally, you also declare variables all willy-nilly, which is generally discouraged in C. To catch that, we always had our students (I used to be a C TA) compile their programs with the following GCC command: "gcc -Wall -Werror -ansi -pedantic". This will turn on all warnings, make all warnings errors, compile in C89 mode, and be really pedantic about C89 syntax (respectively).

    ASimPerson on
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    The assignment previous to this one had me implementing two syscalls, one of which set a variable in the kernel, and the other returned the value of that variable. Granted, we were running things on QEMU (as we are in this program), but I handled it just fine.

    TwistedJester on
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    Ok.... I've got my linked list of files working in the kernel, and it works just fine creating files, writing to them, finding them and deleting them. However, when printing the values out (my syscalls don't actually return the data), printk doesn't seem to like me interpolating strings. It prints out the value, but it seems to append ten or so garbled characters after the name of the file and the data. Is interpolating strings with printk just frowned upon or is there a better means of doing that in the kernel?

    TwistedJester on
  • SmasherSmasher Starting to get dizzy Registered User regular
    edited April 2008
    It seems like the strings aren't being null terminated correctly, though I can't say what's causing it. What exactly do you mean by interpolating strings?

    I don't see any printk's in your code above, so obviously it's changed a little bit. Try posting it again (in a spoiler if you want to save space) so we can see where you're at now.

    Smasher on
  • TwistedJesterTwistedJester Registered User regular
    edited April 2008
    EDIT: Nevermind. I found the mistake, I was stripping off the null terminator in the c program. Stupid stupid stupid.

    TwistedJester on
Sign In or Register to comment.