Why string reversal function in c code not working? - c

Code is crash unexpectedly, any logical error in this code?
Purpose of this code is to reverse the string.
When I try to debug the code, the issue seems in the strrev function. But could not catch up with the exact issue.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *s[]={"To err is hman..",
"man is wild",
"Dream big thought",
"do it myself self",
};
void xstrrev(char *a1,char *a2,char *a3,char *a4)
{
strrev(a1);
strrev(a2);
strrev(a3);
strrev(a4);
}
int main()
{
for(int i=0;i<4;i++)
{
printf("%s\n",s[i]);
}
printf("Hello world!\n");
xstrrev(s[0],s[1],s[2],s[3]);
for(int i=0;i<4;i++)
{
printf("%s\n",s[i]);
}
return 0;
}

This declaration
char *s[]={"To err is hman..",
"man is wild",
"Dream big thought",
"do it myself self",
};
declares an array of pointers to string literals. Though in C (opposite to C++) string literals have types of non-constant character arrays nevertheless you may not change string literals. Any attempt to change a string literal results in undefined behavior.
Instead of the array of pointers declare a two-dimensional character array like
char s[][18] =
{
"To err is hman..",
"man is wild",
"Dream big thought",
"do it myself self",
};
Pay attention to that the function strrev is not a standard C function.

I assume strrev takes a char * pointer to a null-terminated string and reverses the order of the char elememts of the string in place. That means that it cannot be used to reverse a string literal because modification of a string literal results in undefined behavior.
OP's array s contains pointers to string literals that are passed to strrev, resulting in undefined behavior. To prevent that, the code needs to be changed so that the array s contains pointers to modifiable strings. That can be done either by creating each string as a named array of char, or by constructing each string as an anonymous compound literal.
Version using named arrays of char:
static char s_0[] = "To err is hman..";
static char s_1[] = "man is wild";
static char s_2[] = "Dream big thought";
static char s_3[] = "do it myself self";
char *s[] = { s_0, s_1, s_2, s_3 };
Version using compound literals:
char *s[] = {
(char []){ "To err is hman.." },
(char []){ "man is wild" },
(char []){ "Dream big thought" },
(char []){ "do it myself self" },
};
In both of the cases above, the string literals are only being used to initialized arrays of char that are modifiable. The pointers in array s point to these modifiable arrays of char, so there is no problem passing them to strrev.
Regarding strrev, that function is not defined by the C standard, but it might be an extended standard library function of some implementation. All function names beginning with str, mem, or wcs are reserved by the C standard.

Well as #Vlad from Moscow and #kaylum mentioned, that you can't modify the content of an array of pointers to string literals, so rather than that you can do it with allocation, as shown in the below code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ft_strrev(char *str)
{
char keep;
int len;
int i;
int stop;
len = strlen(str);
stop = len / 2;
i = 0;
while (len > stop)
{
keep = str[i];
str[i] = str[len - 1];
str[len - 1] = keep;
i++;
len--;
}
}
void xstrrev(char *a1,char *a2,char *a3,char *a4)
{
ft_strrev(a1);
ft_strrev(a2);
ft_strrev(a3);
ft_strrev(a4);
}
int main()
{
char **s;
s = calloc(sizeof(char*), 5);
s[0] = strdup("To err is hman..");
s[1] = strdup("man is wild");
s[2] = strdup("Dream big thought");
s[3] = strdup("do it myself self");
for(int i=0;i<4;i++)
{
printf("%s\n",s[i]);
}
printf("Hello world!\n");
xstrrev(s[0],s[1],s[2],s[3]);
for(int i=0;i<4;i++)
{
printf("%s\n",s[i]);
}
return 0;
}
and since I can't use strrev() function with my compiler, because This is a non-standard function that works only with older versions of Microsoft C, I did my own reverse function ft_strrev.

Related

Confused between passing strings to a function (C)

Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);

Why am I able to modify char * in this example?

I have problems understanding how char* works.
In the example below, the struses is called by main().
I created a buf to store the const variable because I want to make a modifiable copy of s1, then I just call the sortString().
This version makes sense to me as I understand that char[] can be modified:
#include "common.h"
#include <stdbool.h>
void sortString(char string[50]);
bool struses(const char *s1, const char *s2)
{
char buf[50];
strcpy(buf, s1); // <===== input = "perpetuity";
sortString(buf);
printf("%s\n", buf); // prints "eeipprttuy"
return true;
}
void sortString(char string[50])
{
char temp;
int n = strlen(string);
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (string[i] > string[j])
{
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
}
However, in this version I deliberately changed the type to char* which is supposed to be read-only. Why do I still get the same result?
#include "common.h"
#include <stdbool.h>
void sortString(char *string);
bool struses(const char *s1, const char *s2)
{
char buf[50];
strcpy(buf, s1);
sortString(buf);
printf("%s\n", buf);
return true;
}
void sortString(char *string) // <==== changed the type
{
char temp;
int n = strlen(string);
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (string[i] > string[j])
{
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
}
This is why I think char * is read only. I get a bus error after trying to to modify read[0]:
char * read = "Hello";
read[0]='B';// <=== Bus error
printf("%s\n", read);
The compiler adjusts the type of the parameter having an array type of this function declaration
void sortString(char string[50]);
to pointer to the element type
void sortString(char *string);
So for example these function declarations are equivalent and declare the same one function
void sortString(char string[100]);
void sortString(char string[50]);
void sortString(char string[]);
void sortString(char *string);
Within this function
void sortString(char *string)
there is used the character array buf that stores the copy of the passed array (or of the passed string literal through a pointer to it)
char buf[50];
strcpy(buf, s1);
sortString(buf);
So there is no problem. s1 can be a pointer to a string literal. But the content of the string literal is copied in the character array buf that is being changed
As for this code snippet
char * read = "Hello";
read[0]='B';
printf("%s\n", read); <=== still prints "Hello"
then it has undefined behavior because you may not change a string literal.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
Pay attention to that in C++ opposite to C string literals have types of constant character arrays. It is advisable also in C to declare pointers to string literals with the qualifier const to avoid undefined behavior as for example
const char * read = "Hello";
By the way the function sortString has redundant swappings of elements in the passed string. It is better to declare and define it the following way
// Selection sort
char * sortString( char *s )
{
for ( size_t i = 0, n = strlen( s ); i != n; i++ )
{
size_t min_i = i;
for ( size_t j = i + 1; j != n; j++ )
{
if ( s[j] < s[min_i] )
{
min_i = j;
}
}
if ( i != min_i )
{
char c = s[i];
s[i] = s[min_i];
s[min_i] = c;
}
}
return s;
}
char * does not mean read-only. char * simply means pointer to char.
You have likely been taught that string literals, such as "Hello", may not be modified. That is not quite true; a correct statement is that the C standard does not define what happens when you attempt to modify a string literal, and C implementations commonly place string literals in read-only memory.
We can define objects with the const qualifier to say we intend not to modify them and to allow the compiler to place them in read-only memory (although it is not obligated to). If we were defining the C language from scratch, we would specify that string literals are const-qualified, the pointers that come from string literals would be const char *.
However, when C was first developed, there was no const, and string literals produced pointers that were just char *. The const qualifier came later, and it is too late the change string literals to be const-qualified because of all the old code using char *.
Because of this, it is possible that a char * points to characters in a string literal that should not be modified (because the behavior is not defined). But char * in general does not mean read-only.
Your premise that the area pointed by a char* isn't modifiable is false. This is perfectly line:
char s[] = "abc"; // Same as: char s[4] = { 'a', 'b', 'c', 0 };
char *p = s; // Same as: char *p = &(s[0]);
*p = 'A';
printf("%s\n", p); // Abc
Demo
The reason you had a fault is because you tried to modify the string created by a string literal. This is undefined behaviour:
char *p = "abc";
*p = 'A'; // Undefined behaviour
printf("%s\n", p);
One would normally use a const char * for such strings.
const char *p = "abc";
*p = 'A'; // Compilation error.
printf("%s\n", p);
Demo
Regarding
char * read = "Hello";
read[0]='B';
printf("%s\n", read); // still prints "Hello"
you have tripped over a backward compatibility wart in the C specification.
String constants are read-only. char *, however, is a pointer to modifiable data.
The type of a string constant ought to be const char [N] where N is the number of chars given by the contents of the constant, plus one. However, const did not exist in the original C language (prior to C89). So there was, in 1989, a whole lot of code that used char * to point to string constants. So the C committee made the type of string constants be char [N], even though they are read-only, to keep that code working.
Writing through a char * that points to a string constant triggers undefined behavior; anything can happen. I would have expected a crash, but the write getting discarded is not terribly surprising either.
In C++ the type of string constants is in fact const char [N] and the above fragment would have failed to compile. Some C compilers have an optional mode you can turn on that changes the type of string constants to const char [N]; for instance, GCC and clang have the -Wwrite-strings command line option. Using this mode for new programs is a good idea.
Yout long examples can be reduced to your last question.
This is why I think char * is read only, get bus error after attempt
to modify read[0]
char * read = "Hello";
read[0]='B';
printf("%s\n", read); <=== Bus error
"Hello" is a string literal . Attempt to modify the string literal manifested itself by the Bus Error.
Your pointer is referencing the memory which should not be modified.
How to sort it out? You need to define pointer referencing the modifiable object
char * read = (char []){"Hello"};
read[0]='B';
printf("%s\n", read);
So as you see declaring it as modifiable is not making it modifiable.

C -Implementing strcpy() But Segfault

I have made a strcpy() function
in C, and I am copying words from one array to other not just letters, but when I run it I am getting Segmentation fault what to do?
#include <stdio.h>
void strcpy1(char *dest[], char source[])
{
while ((*dest++ = *source++));
}
int main()
{
char source[3][20] = { "I", "made", "this" };
char dest[3][20];
strcpy1(&dest, source);
//printing destination array contents
for (int i = 0; i < 3; i++) {
printf("%s\n", dest[i][20]);
}
return 0;
}
There are multiple problems in your code:
the prototype for your custom strcpy1 function should be:
void strcpy1(char *dest[], char *source[]);
the arrays source and dest are 2D char arrays: a very different type from what strcpy1 expects, which are arrays of pointers. Change the definition to:
char *source[4] = { "I", "made", "this" };
char *dest[4];
you should pass the destination array as dest instead of &dest
the source array should have a NULL pointer terminator: it should be defined with a length of at least 4. Same for the destination array.
in the print loop dest[i][20] refers to a character beyond the end of the i-th string. You should just pass the string as dest[i].
Here is a modified version:
#include <stdio.h>
void strcpy1(char *dest[], char *source[])
{
while ((*dest++ = *source++));
}
int main()
{
char *source[4] = { "I", "made", "this" };
char *dest[4];
strcpy1(dest, source);
//printing destination array contents
for (int i = 0; dest[i]; i++) {
printf("%s\n", dest[i]);
}
return 0;
}
Note that it is somewhat confusing to name strcpy1 a function that has very different semantics from the standard function strcpy().
The %s specifier is for strings, eg, a char* referring to the first character of a string.
When you pass dest[i][20] to the printf function, it is not a char*. It is a single char, the 21st char (valid indices are 0-19, for a total of 20 elements).
So it is an array-out-of-bounds-index, and also, not a char* as printf expects.
printf("%s\n", dest[i][20]);

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

Is my use of pointers in this C program correct?

For example:
This is what I tried:
#include "stdafx.h"
#include <ctype.h>
char *mystrcat(char *s1p, char *s2p);
char main(void)
{
...........................
}
char *mystrcat(char *s1p, char *s2p)
{
printf("whatever = %s%s\n", s1p, s2p);
return 0;
}
How do I make this work with the 3rd pointer and have it store p1 and p2?
Replace: *mystrcat(string1, string2);
With: char *string3 = mystrcat(string1, string2);
Also if your teacher wants char*'s instead of
char string1[80];
char string2[80];
You could do
char *string1 = malloc(80*sizeof(char));
char *string2 = malloc(80*sizeof(char));
To concat your strings:
char *mystrcat(char *s1p,char *s2p) {
char *cat = malloc(2*80*sizeof(char));
int i = 0;
while(s1p[i]!='\o') {
cat[i] = s1p[i];
i++;
}
int j = 0;
while(s2p[j]!='\o') {
cat[i+j] = s2p[j];
j++;
}
return cat;
}
Bad coding habits aside (I've been doing C for a while, still haven't fixed some of em), there is one error I see: mystrcat(string1, string2). The return type is char, but the function itself has the pointer "in it" (hard to explain). So it should just be mystrcat(string1, string2)
It sounds like you want to write a function to concatenate strings. To do this you need to be able to visualize the strings in your head, the 2 input strings and the resultant string.
Here's an algorithm that should solve it:
Create a result string that has enough space for the total number of characters in the given input plus 1 for the terminating nul char.
Copy the bytes from the first string to the result.
Append the characters from the esconds string to the result
Append a nul character
return the result
Programming is the ability to see a problem, devise an algorithm and then implement in a programming language.
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <ctype.h>
char *mystrcat(char*s1p, char*s2p); // Prototype
int main(void)
{
char *string1 = malloc(80*sizeof(char));
char *string2 = malloc(80*sizeof(char));
printf("Enter in string 1");
scanf("%s", string1);
printf("Enter in string 2");
scanf("%s", string2);
char *mystrcat((string1,string2));
return 0;
}
char *mystrcat(char *s1p,char *s2p)
{
char *cat = malloc(2*80*sizeof(char));
int i = 0;
while(s1p[i]!='\o') {
cat[i] = s1p[i];
i++;
}
int j = 0;
while(s2p[j]!='\o') {
cat[i+j] = s2p[j];
j++;
}
return cat;
}
this is the code i got so far with all of your lots help, i included everthing top to bottom, i am using MSVS 2012 and the reason i am posting this because i have an error on 'malloc' the error as fellows
3 IntelliSense: a value of type "void *" cannot be used to initialize an entity of type "char *" c:\Users\Sid\Documents\Visual Studio 2012\Projects\PORTFOLIO QUESTION 3\PORTFOLIO QUESTION 3\PORTFOLIO QUESTION 3.cpp 32

Resources