Thread: String problem

    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    24
    Rep Power
    0

    Question String problem


    So I was trying to reproduce the function strlen of C:

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

    int lenght[1], i, number, position, position_validated;
    char *cpy_string,*str_final, string;

    int function_strlen(char **arg,int a)
    {
    i=0;
    while (arg[a][i] != '\0') {i++;}
    return i;
    }


    int main(int n_arg,char **arg)
    {
    int a;

    for (a=1;a<3;a++)
    {
    lenght[a-1] = function_strlen(&arg[a],a);
    printf("\n\nString n%d has a lenght of %d.\n",a,lenght[a-1]);
    }
    }

    I simply introduce two arguments in the command line, then the program should return the lenght of both strings. This is what I got after running the program with arguments hello and hi:

    String n1 has a lenght of 2.

    String n2 has a lenght of 20.

    So the first string has lenght of 5 ansd the second lengt of 2. What is going on? :confused: Please help me.
  2. #2
  3. Java Junkie
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jan 2004
    Location
    Mobile, Alabama
    Posts
    4,021
    Rep Power
    1285
    One issue is that the parameter in your function is an array. The actual parameter is a String.
  4. #3
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    First, please use code tags to post code here. It preserves your code's formatting and keeps it from collapsing into an unreadable mess.

    Here is what your code looks like with code tags (original formatting recovered via Reply button):
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int lenght[1], i, number, position, position_validated;
    char *cpy_string,*str_final, string;
    
    int function_strlen(char **arg,int a)
    {
    	i=0;
    	while (arg[a][i] != '\0') {i++;} 
    	return i;
    }
    
    
    int main(int n_arg,char **arg)
    {
    	int a;
    	
    	for (a=1;a<3;a++)
    		{	
    		lenght[a-1] = function_strlen(&arg[a],a);
    		printf("\n\nString n%d has a lenght of %d.\n",a,lenght[a-1]);
    		}
    }
    When I compile it, I get only one warning:
    C:>gcc -Wall toodd1.c
    toodd1.c: In function `main':
    toodd1.c:25: warning: control reaches end of non-void function

    C:>
    The reason for that warning is that while you had correctly declared main to return int, you never return anything! You promised the compiler that you would return an int and then you broke your promise. Never break a promise to the compiler:
    Originally Posted by Henry Spencer
    If you lie to the compiler, it will get its revenge.
    But that's not where this specific problem lies. BTW, the convention is to return zero if the program ran successfully and a positive non-zero if execution had to be aborted (eg, because it didn't get the number and types of arguments it expected, it couldn't open a file, etc).

    Your main problem is that you are making your program overly complex. For example:
    1. You are using too many global variables unnecessarily. For example, i is global, but not only do you not use it outside of the function, function_strlen, you even return its value from that function. And you never even use the rest, except for that array of length one? which, like i, is only used within a single function. IOW, there is absolutely no reason whatsoever for you use any global variables.

    2. Instead of simply passing one of the args to the function, function_strlen, you require that function to have extra knowledge that it should not need, information about where the string is stored and how it is stored. Just pass the string pointer to the function and have it work with that. Not only would you reduce the number of arguments used, but you would be passing a char pointer instead of a pointer to a pointer as you currently do. And the code within the function will be simpler and less error-prone -- the more complicated you make your code, the more likely you are to introduce bugs.

    3. Your for-loop in main is weird (ie, unconventional) and undoubtedly wrong (which is difficult to see because it is weird):
    a. Normally, we iterate from zero only so long as we're less than the test value. Then if we want to do anything with the both the current and the next elements, we would index them with a and a+1.

    b. Why a test value of 3? Why not make use of n_arg, which the OS passes to you and which is the number of arguments in arg[]? (BTW, normally we name them argc and argv[])

    Now, what's killing your program is this:
    Code:
    int lenght[1], i, number, position, position_validated;
    How many elements are in that array? One!
    What is its name? lenght[0].
    Does a second element, lenght[1], exist? No, it doesn't.
    Do you try to write to lenght[1]? Yes, you do.
    What happens when you do that? You overwrite whatever is sitting in memory after lenght. That is to say, you clobber other data.
    What will that clobbering cause to happen? Unpredictable, since it all depends on exactly what is being clobbered and exactly how it is being used. That can vary from compiler to compiler, so it cannot be predicted. Though a common symptom can be your program crashing.

    I copy-and-pasted your program, compiled it with the warning I posted above, and ran it with the same arguments you describe:
    C:>a hello hi


    String n║1 has a lenght of 2.

    C:>
    And then it crashed. One line of output and then it crashed before displaying a second line.

    So I increased the length of that array and tried it again. It crashed again. Then I played with the second argument:
    C:>a hello hi


    String n║1 has a lenght of 2.

    C:>a hello high


    String n║1 has a lenght of 4.

    C:>
    So then, what your code is actually doing is this:
    The first time through the for-loop, you process the second argument, "hi".
    The second time through, you process the third argument, which does not even exist. So when I try to access the third, nonexistent, argument, I crash because of an access violation.

    My recommendation: Clean up and simplify your code in accordance with the suggestions I have made above.

    Further simplification: get rid of the lenght array and just make it an int that is declared locally within main.

    BTW, when I played with supplying a third argument, this is what I got:
    C:>a hello hi Hej!


    String n║1 has a lenght of 2.

    C:>
    And it still crashed! So something else is going on, but your code is far too weird for it to be readily apparent. Clean your code up and be back with us.

    PS
    I made the changes that I had recommended to you and this is what I got:
    C:\otros\dcw>a hello hi


    String n║1 has a lenght of 5.


    String n║2 has a lenght of 2.

    C:\otros\dcw>
    And it did not crash. The only other adjustment I made was to use n_arg-1 as the test value instead of n_arg.
    Last edited by dwise1_aol; November 2nd, 2013 at 02:17 PM.
  6. #4
  7. Contributing User

    Join Date
    Aug 2003
    Location
    UK
    Posts
    5,109
    Rep Power
    1802
    You have defined function_strlen() to take the entire command line argument array, but are then passing &arg[a] while incrementing a.

    Either you need to change the call to:

    Code:
    lenght[a-1] = function_strlen(arg,a);

    Or you need to change function_strlen() thus:

    Code:
    int function_strlen(char **arg )
    {
        i=0;
        while (arg[0][i] != '\0') {i++;} 
        return i;
    }
    with the call changing to:
    Code:
    lenght[a-1] = function_strlen(&arg[a]);
    Both solutions rather expose the rather ludicrous and over complex interface you have defined. If you want to write a strlen implementation, why would you change the interface?

    Code:
    int function_strlen(const char* arg )
    {
        int i=0;
        while( arg[i] != '\0') {i++;} 
        return i;
    }
    
    int main(int n_arg,char **arg)
    {
        for( int a = 0; a < 2; a++ )
        {	
            printf("\n\nString n%d has a length of %d.\n", a, function_strlen( arg[a] )  ) ;
        }
    }
    Other issues with your code were the buffer overrun of length[], and the unnecessary use of global variables, and superfluous variables in any case. Arrays in C are indexed from 0, rinning a loop from 0 to 1 makes far more sense that 1 to 2, only to then gave to perform arithmetic on every array access.
    Last edited by clifford; November 2nd, 2013 at 03:43 PM.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    24
    Rep Power
    0

    Smile I figured it out!


    OK, so i edited the code again. Here is it:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int length[2], i;
    
    int function_strlen(const char *arg)
    {
    	i=0;
    	while (arg[i] != '\0') i++;
    	return i;
    }
    
    
    int main(int n_arg,char **arg)
    {
    	int a;
    	for (a=0;a<2;a++)
    		{	
    		length[a] = function_strlen(arg[a+1]);
    		printf("\nString n%d has a length of %d.\n\n",a+1,length[a]);
    		}
    }
    Sorry about the extra variables I left in the original code. This is only a part of the whole code and I forgot to erase those variables. So the program is working now and I simplified it.

    The reason why length is an array is that there are two strings and i need to keep the length of each one for next steps of the program.

    Anyway, the main problems in my code (beyond the fact that it was a little bit messy ^^ Sorry about that...) were that I was passing the array "arg" to the fonction in a wrong way and that length should have been declared has length[2] (lol it was so obvious...)
    I corrected the first one with: "lenght[a] = function_strlen(arg[a+1]);" passing to function ---> "function_strlen(const char *arg)".

    Thanks for all you who answered my question :)
  10. #6
  11. Contributing User

    Join Date
    Aug 2003
    Location
    UK
    Posts
    5,109
    Rep Power
    1802
    Originally Posted by Toodd
    Sorry about the extra variables I left in the original code. This is only a part of the whole code and I forgot to erase those variables. So the program is working now and I simplified it.
    The "superfluous variables" included the ones that you actually used. A global variable in any case is usually a signe of poor design, and in this case they are entirely unnecessary (as in my last example).

    Originally Posted by Toodd
    The reason why length is an array is that there are two strings and i need to keep the length of each one for next steps of the program.
    Maybe so, but it still need not be a global.

    Take a look at this article . Although it refers to embedded systems, it is no less relevant to desktop systems.

IMN logo majestic logo threadwatch logo seochat tools logo