# C newbie question



## Business_Woman (Sep 1, 2009)

Hai,

Trying to write a function to calculate string length.


```
int strnlen(char *str){
         
     while(*str != '\0'){
                 str++;
     }
     return (int)str;
     }
```

But that won't work, why?


----------



## avilla@ (Sep 1, 2009)

is that returning big, big numbers? if str is the pointer to the char[], it won't start at 0... better do that with a counter...


```
for (i = 0; str[i] != '\0'; ++i)
        ;
return i;
```

...or, if you want to keep it that way, record the value of str at the beginning and subtract it from str when returning...


```
for (str_init = str; *str != '\0'; ++str)
        ;
return (int)(str - str_init);
```

it *should* work, but it doesn't make sense)


----------



## ephemera (Sep 1, 2009)

```
return strchr(str,0)-str;
```


----------



## avilla@ (Sep 1, 2009)

ephemera said:
			
		

> ```
> return strchr(str,0)-str;
> ```



if you're going to include <string.h>, then you have strlen() too...


----------



## Business_Woman (Sep 1, 2009)

I found a way that works


```
int strlen(char *str){
    
    char *p = str;
    while(*p != '\0'){
             p++;
    }        
             return p-str;
             }
```

But what is the value of str?


----------



## ephemera (Sep 1, 2009)

Yup you are right.


----------



## avilla@ (Sep 1, 2009)

Business_Woman said:
			
		

> I found a way that works
> 
> 
> ```
> ...



which is exactly the second example i made, with a while in place of the for (not elegant, and longer) 
anyway i suggest using my first example



> But what is the value of str?



str is the pointer to the array of characters (the string), and it contains the address of memory to which it refers (which is the initial address of the array of characters). *str is, as you seem to know, the value stored in that memory cell


----------



## Business_Woman (Sep 1, 2009)

Thanks, but what i meant was why subtract str from p?


----------



## SirDice (Sep 1, 2009)

Ok.. First off, pointer arithmetic is a bad, bad idea. Sooner or later you will shoot yourself in the foot with it.

Now, lets explain

```
int strlen(char *str){
    
    char *p = str;
    while(*p != '\0'){
             p++;
    }        
    return p-str;
}
```

Str will be a pointer to a memory address where your string starts. P is also a pointer and you've assigned it the value of str. Now both p and str point at the same memory location.

By incrementing p until the end of the string it will point to the last address. Subtracting the last address from the first (where str is still pointing to) you get the number of bytes. Ergo, the string length.


----------



## ephemera (Sep 1, 2009)

Memory is made up of bytes and is numbered from 0 to whatever amount you have available on your m/c.

strlen() is called with str pointing to the string (say) "hello" already stored in memory starting at address (say) 756, like shown below:


```
---------------------------
... |h |e |l |l |o |\0| ...
---------------------------
     ^
     str(756)
     ^
     p(756)
```

After _char *p = str;_ both str and p contain the address (or point to mem. location) 756.

If you dereference a pointer you get whats stored in its mem. location. For example *str will give the ASCII char. 'h'.

After the while loop exits you have:


```
---------------------------
... |h |e |l |l |o |\0| ...
---------------------------
     ^              ^
     str(756)       p(761)
```

Subtracting the pointers str and p gives p-str = 761-756 = 5


----------



## SirDice (Sep 1, 2009)

ephemera said:
			
		

> Memory is made up of bytes and is numbered from 0 to whatever amount you have available on your m/c.


Technically, every process gets it's own 4GB address space regardless of the amount of physical memory you have


----------



## ephemera (Sep 1, 2009)

SirDice said:
			
		

> Technically, every process gets it's own 4GB address space regardless of the amount of physical memory you have


Sure, but we don't want to overwhelm a newbie who is struggling to understand pointers.


----------



## Business_Woman (Sep 1, 2009)

Thnak you Ephemera, SirDice. 
I think i understand


----------



## vivek (Sep 1, 2009)

Why reinvent wheel (learning may be objective here, in that case open headers and related files) ? Just use provided functions.


----------



## SirDice (Sep 1, 2009)

vivek said:
			
		

> Why reinvent wheel (learning may be objective here, in that case open headers and related files) ? Just use provided functions.



IMO making your own functions even if the same standard function already exist will increase your knowledge. So I think it's good to do stuff like this, learn how it works and then use the already provided functions :e


----------



## papanyanz (Sep 4, 2009)

Your own fnction will work 10000 times slower than one provided by c library. Try to compare them - run in the loop for an 1000000 times and use timers to get intervals... 

Library functions recently use hardware capabilities to speed up execution ...
try to write your own "bitblt"-like - you'll see how each pixel was drawn


----------



## Business_Woman (Sep 5, 2009)

Hi, i have just one last question 

After the sucess with the strlen function i tried to write my own version of strcpy, but something must be wrong because my program segfaults when trying to use it.

I want the function to return a pointer to the copied string


```
char *strcopy(const char *src, char *dest){

while(*dest++ = *src++);

return dest;
}
```

Also what is the difference between
char *p;

*p = 'p'
*p = "p"
Do i still have to point p somewhere?, and where would that be?

//thanks


----------



## mickey (Sep 6, 2009)

Business_Woman said:
			
		

> I want the function to return a pointer to the copied string
> 
> 
> ```
> ...



Because you are incrementing your dest pointer, while copying the string, in the end it will point to the memory location right after the end of the destination string. Using that
pointer surely gives a segfault. You would need to save a copy
of the original dest pointer and return that instead.



> Also what is the difference between
> char *p;
> 
> *p = 'p'


This assigns the ASCII code of the letter 'p' to the memory location p points to.



> *p = "p"


This assigns a pointer to the memory location of the NUL
terminated string "p" to the memory location, where p points to.
As p is a "char *", this does not make much sense anyways. It
could make sense if p was of type "char **".



> Do i still have to point p somewhere?, and where would that be?



p must point to a memory location, owned by and writable by the process. Otherwise a segfault is for sure. This could for example be the memory of an automatic variable, as in

```
char str[256];
char *p = &str;
```
or a memory block, allocated by means of malloc(), calloc(), etc.


----------



## Alt (Sep 6, 2009)

Business_Woman said:
			
		

> Also what is the difference between
> char *p;
> 
> *p = 'p'
> ...


You will got segfault this way, cus char* is only pointer, he not own any memory. When you assign this way will write to random memory location what leads to segfault


----------



## Eponasoft (Sep 6, 2009)

papanyanz said:
			
		

> Your own fnction will work 10000 times slower than one provided by c library. Try to compare them - run in the loop for an 1000000 times and use timers to get intervals...
> 
> Library functions recently use hardware capabilities to speed up execution ...
> try to write your own "bitblt"-like - you'll see how each pixel was drawn


I think you're missing the point...


----------



## papanyanz (Sep 7, 2009)

Eponasoft said:
			
		

> I think you're missing the point...



Sorry for my incomplete english knowledge,but what i miss ?


----------



## ephemera (Sep 7, 2009)

papanyanz said:
			
		

> Your own fnction will work 10000 times slower than one provided by c library. Try to compare them - run in the loop for an 1000000 times and use timers to get intervals...


Here's an i386 optimised version of strlen() from Solaris: 
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/i386/gen/strlen.s

Haven't benchmarked it but looking at the code it's obvious that it won't give anything like the 10000x speed improvement you mentioned - more likely a single digit factor of increase in speed. 

There is a reduction in memory access (~4x) but since both the programs are cache friendly (picture perfect spacial locality of reference) I think the main speed improvement is coming from the ~4x reduction in number of branches (working with a word at time instead of byte).


----------



## Alt (Sep 7, 2009)

She just doing exercises - why you boring about it :/


----------



## papanyanz (Sep 8, 2009)

Alt said:
			
		

> She just doing exercises - why you boring about it :/


That's good - maybe this is the best way to learn pointers and string manipulations.What i wanted to say - that in real applications use ONLY library ones...



> Here's an i386 optimised version of strlen() from Solaris:
> http://src.opensolaris.org/source/xr...6/gen/strlen.s
> 
> Haven't benchmarked it but looking at the code it's obvious that it won't give anything like the 10000x speed improvement you mentioned - more likely a single digit factor of increase in speed.


Well - how about memcpy please? Just now i've no time to check code - if it uses much advanced techniques...
Anyway  - there was a time when i was wondering,why

```
for (int i=0;i<=1000000;i++) a[i]=b[i];
```
is working twice slower compared to 

```
for (int i=0;i<=500000;i++) {
a[i]=b[i];
a[i+500000]=b[i+500000];
}
```


----------



## Eponasoft (Sep 8, 2009)

That's because of the overhead of the 'for' loop in PHP. Assignments, even of arrays, are much faster than a loop pass. So being able to do two assignments per pass at different offsets is going to be faster than one assignment per pass. It's probably the same in normal C code, though I imagine that the difference isn't going to be so huge.


----------

