Thread: Now it works, now it won't

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    20

    Question Now it works, now it won't

    Hello. I'm trying to learn C using K&R. I've had some background with Scheme and Java programming so I'm guessing that K&R is the path to take to learning C.

    Earlier in the text, I wrote the following program, which allows the user to input a series of lines until EOF is invoked. Then, the program will print out the longest line entered by the user. Here's the code:

    Code:
    #include <stdio.h>
    #define MAXLINE 1000
    
    int getline(char to[], int max){
    	int count = 0;
    	int c;
    	
    	while((c = getchar()) != '\n'){
    		to[count] = c;
    		count++;
    	}
    	
    	return count;
    }
    
    void copy(char to[], char from[]){
    	int i = 0;
    	
    	while((to[i] = from[i]) != '\0'){
    		i++;
    	}
    }
    
    main(){
    	char text[MAXLINE][MAXLINE];
    	char longestline[MAXLINE];
    	int i = 0;
    	int largest = 0;
    	int linelength = 0;
    	
    	linelength = getline(text[i], MAXLINE);
    	while(text[i][0] != EOF){
    		if(linelength > largest){
    			largest = linelength;
    			copy(longestline, text[i]);
    			printf("%s%c", longestline, '\n'); //this part works (HEY)
    		}
    		
    		linelength = getline(text[i], MAXLINE);
    	}
    	
    	printf("%s", longestline);
    }
    Note that the line shouting HEY was just added to aid in debugging.

    The way I understand how my program works, it seems that, called from main with the (main local?) variable longestline as an argument, the function copy copies the contents of [I]text into longestline such that, I can access its new value from main. (See the printf line shouting HEY right after the call to copy).

    So far so good.

    Then, I wrote a program which removes the "0x" part in hexadecimal numbers. Here is my code:

    Code:
    #include <stdio.h>
    #include <string.h>
    
    void removeOX(char hex[]){
    	int i = 0;
    	int limit = strlen(hex);
    	
    	while(i < limit){
    		if(hex[i] == 'x'){
    			int j = 0;
    			int foo = i + 1;
    			char Xremoved[limit - i];
    			//printf("%s", "caught here");
    			while(j < (limit - i)){
    				Xremoved[j] = hex[foo];
    				j++;
    				foo++;
    			}
    			
    			Xremoved[limit - i] = '\0';
    			printf("%s%s%s", "from removeOX: ", Xremoved, "\n");
    			hex = Xremoved;
    			printf("%s%s%s", "from removeOX hex: ", hex, "\n");
    			break;
    		}
    		else{
    			i++;
    		}
    	}
    }
    
    int main(){
    	char love[] = "0x8f";
    	
    	removeOX(love);
    	printf("%s", love); //This bit doesn't work now!
    }
    Again, printf lines were added to aid in debugging.

    The way I understand it, my use of functions are simillar here, i.e. they follow the following pattern:

    1) Declare a variable in main.
    2) Invoke a function, pass the variable declared in 1 to that function.
    3) Function modifies its argument(s). Since I passed a declared variable, this declared variable also changes, as the function operates on its arguments.
    4) modified argument == modified variable. I may now use the variable with its value modified.

    I wonder what am I getting wrong here. Any help would be greatly appreciated. Much thanks.

    (Note: I just started learning pointers and I tried to write the "0x" remover with pointers. No luck so far. However, my main concern for now is on my understanding of functions. How come the first one works and the "0x" remover won't?

    In any case, should it seem appropriate, feel free to include pointers in your discussion .

    Much thanks )

  2. #2
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Note that an array name is not a variable so it cannot be assigned to ie it's not an lvalue.
    So all the processing done in removeOX() is lost after it returns because love still points to the original string.
    Your best bet is to return a pointer instead of void from removeOX() to the hex string minus the leading "0x".

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Your observations on the K&R code are correct. However, it's a bit more subtle than it appears, which is why your code is not working as you expect.

    The first thing to know is that C is a pass by value language. When you pass an object into a function, only a copy is passed. When you modify that object in the function, it is not changed in the caller:
    Code:
    #include <stdio.h>
    static void f(int i)
    {
      i = 10;
    }
    int main(void)
    {
      int i = 5;
      f(i);
      printf("%d\n", i); /* i is still 5 */
      return 0;
    }
    So why does K&R's copy() function work? Because of one of the dark secrets of C: you can't actually pass an array to a function. When you pass an array, C goes behind your back and passes a pointer to the beginning of the array. It is through the magic of pointers that you can simulate pass by reference in C, and thus change the original value. But you can't just use the = operator to assign a new value to the pointer! This is, perhaps, the confusing part: the pointer is still passed by value. That is, the function gets a copy of the pointer. So when you do:
    Code:
    static void f(char foo[]) /* foo is actually a pointer here, despite the [] syntax */
    {
      foo = new_value;
    }
    The pointer "foo" now points to "new_value", but only in this function. The original array is not modified at all! Instead you have to modify what the pointer points to. This is accomplished (among other ways) with the [] operator:
    Code:
    static void f(char foo[])
    {
      foo[0] = 'x';
    }
    Now the first character of the array you pass in is changed to an 'x'. foo points to the original data, and so you can indirectly go there by dereferencing the pointer (which is what the [] operator does). You have a copy of the pointer, but it still points to the original data! So in your function, when you do hex = Xremoved you're just pointing your local variable "hex" to "Xremoved", and after the function exits, nothing has changed. You can use strcpy() to copy Xremoved into hex, and that will persist after the function returns.

    But before you do that, you'll have to look at your code that copies into Xremoved. Xremoved is an array of (limit - i) size. That means the last element of the array must be (limit - i - 1). To make this clear, say you have an array of size 3: this only has elements 0, 1, and 2. Your code is writing one byte beyond the end of the array.

    Despite the fact that pointers and arrays get jumbled up like this, it's important to remember that they are distinct. You can, most of the time, treat an array like a pointer but it is not a pointer, and there are a few times where this distinction matters.

  4. #4
    Registered User
    Join Date
    Nov 2009
    Posts
    20
    cas you got it all...much thanks. I'll have more light now in tackling this problem. Will try it out again as soon as I get some sleep...Again, thanks (--,)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 08-04-2009, 08:57 AM
  2. Can anybody show me why this works??
    By tzuch in forum C Programming
    Replies: 2
    Last Post: 03-29-2008, 09:03 AM
  3. fprintf works in one function but not in the other.
    By smegly in forum C Programming
    Replies: 11
    Last Post: 05-25-2004, 03:30 PM
  4. Programs works one way, not another. VC++ 6.0 help.
    By Cheeze-It in forum Windows Programming
    Replies: 4
    Last Post: 12-10-2002, 10:29 PM
  5. it never works...
    By Ryce in forum Game Programming
    Replies: 5
    Last Post: 08-30-2001, 07:31 PM

Tags for this Thread