Error with mystrlen function - c

I was trying to write out some of the implementations of the string functions available in C. My code is:
#include <stdio.h>
#include <stdlib.h>
char *mystrcpy(char *s1, char *s2)
{
while(*s1++ = *s2++);
return s1;
}
int mystrlen(char *s)
{
int len = 0;
while(*s != '\0')
{
len++;
}
return len;
}
int main(void)
{
char arr = "Hi";
char arr1[10];
char arr2[] = "Hello";
int length;
mystrcpy(arr1, arr2);
printf("%s", arr1);
length = mystrlen(arr);
printf("%d", length);
return 0;
}
mystrcpy works fine, but the other method mystrlen does no execute. What could be the error? The following is the program termination note:
Process terminated with status -1073741510 (0 minutes, 4 seconds)
Also, there are few warnings related to casts. Is there any place in the code where I should be using any cast?

First, your mystrlen has an infinite loop.
Fixed code:
int mystrlen(const char *s)
{
int len = 0;
while (*s++ /* increment to next character every loop */ != '\0')
{
len++;
}
return len;
}
Also added const since you never change the data referred to by *s
Second, the assignment: char arr="Hi"; is not valid.
You are attempting to assign a char[] array to a char variable. The correct form would be one of the following:
char arr[]="Hi"; // array syntax
char *arr="Hi"; // pointer syntax
Given your invalid arr assignment, your runtime error is most likely caused by mystrlen attempting to incorrectly deference arr.
What compiler are you using? Most conforming compilers should have caught the second issue. If using GCC, add the -Wall flag to your makefile.

This:
char arr="Hi"; /* Should have caused compiler warning,
as is attempting to assign a char
to a char[3]. */
should be:
char arr[] ="Hi";
or:
char* arr = "Hi";

Related

Why is this code getting a segmentation fault?

I am trying to write a function that deletes a char c from a string src, and I am getting a seg fault when I try to run it. Here is the function.
void removeChar(char *src, char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++){
if (src[i] != c){
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
}
And here is the main function where I am calling it.
int main(int argc, char **argv){
char *str = "Hello, world!\0";
printf("%s\n", removeChar(str, 'l'));
}
the return type of this function removeChar(str, 'l') is void not an char array and you are passing this to
printf("%s\n", removeChar(str, 'l'));
so here %s may give you the segmentation fault.
You assigned pointer src by the address of the first element of a local array
src = str1;
that will be destroyed after exiting the function. Moreover variable src is a local variable of the function so any changes of it do not influence the original pointer str.
Take into account that you may not change string literals. Any attempt to change a string literal results in undefined behaviour of the program.
Also the function has return type void and may not be used as an outputed object in function printf.
Type void is an incomplete type. It has no values.
And there is no need to append explicitly terminating zero to a string literal as you did.
"Hello, world!\0"
String literals already have terminating zeroes. So you could write simply
"Hello, world!"
As I already answered this question then you can visit my personal forum where there is a realization of the corresponding valid function.
If to declare correctly the function like
char * removeChar( char *s, char c );
then the main will look the following way
int main(int argc, char **argv)
{
char str[] = "Hello, world!";
printf( "%s\n", removeChar( str, 'l' ) );
}
You can print the string in the function itself! Then it works:
#include <stdio.h>
#include <string.h>
void removeChar(char src[], char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++) {
if (src[i] != c) {
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
printf("%s\n", src);
}
int main(int argc, char **argv) {
char str[] = "Hello, world!";
removeChar(str, 'l');
return 0;
}
You have several bugs:
char *str = "Hello, world!\0";. Setting a non-constant pointer to point at a string literal is always wrong. Instead, declare the variable as const char *str. See this FAQ.
removeChar doesn't return anything so you can't pass it as a parameter to be printed by printf. Your compiler really should have complained here. Chances are that your compiler is misconfigured or you you aren't using it with all warnings enabled.
char str1[100]; You cannot use local variables and then try to pass the contents on to the caller. See this FAQ.
src = str1; doesn't do a thing, since src is only a local copy of the original pointer. With this assignment, you will not change the address of str in main. Which would have been a bug anyway, because of 3) above. You should rewrite your program so that is only uses src and no temporary array.
Not have enough reputation to comment. So, I had to write this on answer:
As Vlad from Moscow pointed out,
`a local array do not exist after the function terminate`
I suggest you obey the same principle as of standard library functions. If you didn't already notice,none string.h function allocate memory for the user. You must allocate before call.
char *str = "Hello, world!\0";
The above code do not guarantee a modifiable memory. The compiler can set them in read only memory. You should use a array instead.

Conflicting types for 'reverse_string' function

I was using this SO question as part of a program that needs to reverse a string. The problem I am having is that I cannot seem to get the function to work. Here is the code I have:
int main(int argc, char *argv[]){
char *test = "Testing";
fputs(test, stdout);
fputs(reverse_string(test), stdout);
}
char* reverse_string(char *str){
char temp;
size_t len = strlen(str) - 1;
size_t i;
size_t k = len;
for(i = 0; i < (len +1)/2; i++){
temp = str[k];
str[k] = str[i];
str[i] = temp;
k--;
}
return str;
}
I am getting an error that there is conflicting types for 'reverse_string'
Edit: For anyone wondering here is the code that works. See #chux's answer for an explanation.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* reverse_string(char *str){
char temp;
size_t len = strlen(str) - 1;
size_t i;
size_t k = len;
for(i = 0; i < (len +1)/2; i++){
temp = str[k];
str[k] = str[i];
str[i] = temp;
k--;
}
return str;
}
int main(int argc, char *argv[]){
char test[] = "Testing";
fputs(test, stdout);
fputs(reverse_string(test), stdout);
}
You can not pass a const char * to a char *
char *test = "Testing";
fputs(reverse_string(test), ... // bad, attempting to change constant data.
// bad as reverse_string() is assumed to return int, but fputs() expects char *
char* reverse_string(char *str) { // Bad, there's now a function conflict
Instead
char* reverse_string(char *str); // Need to declare/define function first
char test[] = "Testing";
fputs(reverse_string(test), ... // good
[Edit]
You problem was well identified (missing function declaration) by others. My suggestion takes care of the next problem. In C, a missing declaration of a function will assume int reverse_string(...) which does not match char* reverse_string(char *str).
[Edit]
As #Shafik Yaghmou suggests, modifying a string literal char *test = "Testing" will result in undefined behavior. Hence the char test[] = "Testing" which initializes test with "Testing\0", but may be modified.
[Edit]
#GreenAsJade correctly points out OP's original error message is due to the assumed int reverse_string(...) supplying an int to s in int fputs(const char * s, FILE * stream);
char *test1 = "Testing" is not the same thing as char test2[] = "Testing". test1 becomes a char * with the size of a pointer. The initial pointer value is to a string "Testing" located elsewhere in memory. test2 is a char array with size 8: length of "Testing" + 1 for '\0'. The array test2 is initialized with 'T', 'e', ... '\0' etc.
FWIW:
(h2hh)momerath:Documents mgregory$ cat test.c
char* reverse_string(char *str) {
return str;
}
char *test = "Testing";
int main() {
reverse_string(test);
}
(h2hh)momerath:Documents mgregory$ gcc test.c
(h2hh)momerath:Documents mgregory$
I think that the answer to the OP's question is that reverse_string has to be declared before being used, to be not int.

Use pointer math instead of array indexing

I'm trying to solve a problem found on my C programming book.
#include <stdio.h>
char *f (char s[], char t[], char out[]);
int main(void)
{
char s[] = "ISBN-978-8884981431";
char t[] = "ISBN-978-8863720181";
char out[10];
printf ("%s\n", f(s,t,out));
return 0;
}
char *f (char s[], char t[], char out[]) {
int i;
for (i=0; s[i] == t[i]; i++)
out[i] = s[i];
out[i] = '\0';
return &out[0];
}
As you can see from the code, this code uses as return value &out[0]: does this means that the complete array is used as return value?
char *f (char s[], char t[], char out[]);
int main(void)
{
char s[] = "ISBN-978-8884981431";
char t[] = "ISBN-978-8863720181";
char out[10];
printf ("%s\n", f(s,t,out));
return 0;
}
char *f (char s[], char t[], char out[]) {
for (; *(s+=1) == *(t+=1);)
*(out+=1) = *s;
*(out+1) = '\0';
return out;
}
This is my proposed solution, but while the proposed code returns "ISBN-978-88", mine only returns "8".
The array is smaller than the lenght of the string, how the proposed code can work without any kind of overflow?
Thanks for your responses.
Your code is too aggressive on side effects: the += 1 operation (which is more commonly denoted simply as ++) should be applied after the copy to the output has been made, not after the comparison.
In addition, you need to save the value of the out buffer before incrementing the pointer, so that you could return a pointer to the beginning of the copied string.
char *orig = out;
for ( ; *s == *t ; s++, t++)
*out++ = *s;
*out = '\0';
return orig;
Demo on ideone.
Your code is returning a pointer to the end of the out array. Not the start. You need to stash the initial value of out and return that.
As an aside, the fact that you can do assignments inside a comparison doesn't mean it's a good idea. That code is going to be very hard to maintain.
&out[0] is equivalent to out. Since arrays in C are passed by reference, in a sense, yes it does return the entire array.
Your solution only prints "8" because you're returning a pointer into the middle of the array. When it tries to print the string, it has no way of knowing that it's in the middle of the array/string, thus you only get a substring printed.

Producing uppercase letters without pointers

I am trying to write a function, uppercase, that converts all lowercase characters in a string into their uppercase equivalents.
However, I am getting a Bus 10 error in my code. I know that string literals cannot be modified in C; so, I am not sure if this is the right approach.
My code is below:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
int uppercase(char source[])
{
int i;
for(i=0; i<=strlen(source); ++i)
if (source[i]>= 'a' && source[i]<= 'z')
source[i]= source[i]-'a' +'A';
else
source[i]=source[i];
}
int main(){
uppercase("cold");
return 0;
}
Ideally this function should return COLD.I suppose the error lies in my whole if statement.
The reason you get a crash is that your code modifies a string literal. Characters inside string literals are placed in protected memory area, and therefore may not be changed: it us undefined behavior.
Replace this
uppercase("cold");
with this:
char cold[] = "cold";
uppercase(cold);
Now the characters of the string are placed in a modifiable area of memory, allowing you to make changes as needed.
Your absolutly working with pointers without even to know it.
In your function definition
int uppercase(char source[])
char source[] is considered by the compiler as a pointer to char (char *source)
So when passing a string literal to uppercase() your just passing it's adress. Then in your function your trying to modify it which leads to undefined behaviour.
Also you can't return a whole array so you just return a pointer to it.
char *uppercase(char source[])
{
int i;
size_t len = strlen(source);
char *tmp;
tmp = malloc(len+1);
if (tmp!=NULL){
memcpy(tmp, source, len+1);
for(i=0; i<len; ++i){
if (tmp[i]>= 'a' && tmp[i]<= 'z'){
tmp[i]= tmp[i]-'a' +'A';
}
}
}
return tmp;
}
Then:
int main(){
char *str = uppercase("cold");
printf("%s", str);
free(str);
return 0;
}
You complete code: http://ideone.com/BJHDIF

simple strcat implementation with pointers

so I was practicing writing c code with pointers using the K&R. For one problem with strcat function, I couldn't find out what was wrong with my code, which according to Visual Studio, returned the destination string unchanged after the strcat function. Any suggestion is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcat(char* s, char* t);
int main(void)
{
char *s="hello ", *t="world";
strcat(s,t);
printf("%s",s);
return 0;
}
int strcat(char* s,char* t)
{
int i;
i=strlen(s)+strlen(t);
s=(char*) malloc(i);
while(*s!='\0')
s++;
while('\0'!=(*s++=*t++))
;
return 0;
}
I'm pretty sure that strcat returns a char* in the real implementation (holding the original value of the first string).
strcat is not supposed to alter the first parameter's address, so you shouldn't call malloc.
Point #2 means that you need to declare char *s as char s[20] in main (where 20 is some arbitrary number big enough to hold the whole string).
If you really want to alter the value of the an input parameter you will need to pass the address of the value - so it would need to be strcat(char **s, ...) in the function declaration/definition, and called with strcat(&s, ...) in main.
1) defining string in this way
char *s="hello "
means that you are defined a literal string. a literal string is saved into read only memory so you can not edit it
you have to define your string as a char array in order to be able to edit it
char s[100] = "hello ";
2) when you define your function in this way
int strcat(char* s,char* t)
you can not change the address of s into the function strcat(). So assigning memory with malloc() into the function will not change the s address when leaving the function
3) change your function strcat to
int strcat(char** s,char* t)
{
int i;
char *u, *v;
i=strlen(*s)+strlen(t);
v = *s;
u=(char*) malloc(i+1);
while(*v!='\0')
*u++ = *v++;
while('\0'!=(*u++=*t++));
*s = u;
return 0;
}
and you call it in the main with:
char *s="hello ", *t="world";
strcat(&s,t);
In
strcat(char* s, char* t)
the 's' is send by value. The value of 's' at call time is copied into the stack then strcat() is call. At the return of strcat the modified version is discard from the stack. So the calling value of 's' is never changed (and you create a memory leak).
Beward, in C every memory cell can be change, even parameters or instructions sections; some changes can be very hard to understand.
Since you are trying to do like the real strcat it's said that the first parameter
The string s1 must have sufficient space to hold the result.
so you don't need to use malloc
char *strcat(char* s, const char* t);
int main(void)
{
char s[15] = {0}; //
char *t = "world"; //const char * so you can't change it
strcpy(s, "Hello ");
strcat(s,t);
printf("%s\n",s);
return (0);
}
char *strcat(char* s, const char* t)
{
int i = 0;
while (s[i] != '\0')
i++;
while (*t != '\0')
s[i++] = *t++;
s[i] = '\0'; //useless because already initialized with 0
return (s);
}
#include<stdio.h>
#include<string.h>
#define LIMIT 100
void strcatt(char*,char*);
main()
{
int i=0;
char s[LIMIT];
char t[LIMIT];
strcpy(s,"hello");
strcpy(t,"world");
strcatt(s,t);
printf("%s",s);
getch();
}
void strcatt(char *s,char *t)
{
while(*s!='\0')
{
s++;
}
*s=' ';
++s;
while(*t!='\0')
{
*s=*t;
s++;
t++;
}
*s=*t;
}
Dear user,
you don't have to complicate things that much. The simpliest code for strcat, using pointers:
void strcat(char *s, char *t) {
while(*s++); /*This will point after the '\0' */
--s; /*So we decrement the pointer to point to '\0' */
while(*s++ = *t++); /*This will copy the '\0' from *t also */
}
Although, this won't give you report about the concatenation's success.
Look at this main() part for the rest of the answer:
int main() {
char s[60] = "Hello ";
char *t = "world!";
strcat(s, t);
printf("%s\n", s);
return 0;
}
The s[60] part is very important, because you can't concatenate an another string to it's end if it doesn't have enough space for that.

Resources