Program to conjugate - c

I am trying to write a program that will conjugate a verb in multiple forms.
So I write a function that will allow me to get the part that is kepted and conjugate it. Fixed rule : whole word except last 2 chars.
I am used to OO, and I can't seem to make it work, while it seems a basic program.
I obtain something with weird : here is a screen at the end of the execution, that will be more explicit
I think I missed a little something in my course (probably in the char[] part...), that has a huge impact, but I can't seem to find it.
I am opened to all observations on my code, since I am beginning, and I prefer going on a solid basis right now, better that later.
Here is the code
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
void RacineVerbe(char verbeEntier[], char dest[]);
int myStrLen(char *s);
int main()
{
char *string;
char *racine;
string = (char*)malloc(200*sizeof(char));
racine = (char*)malloc(200*sizeof(char));
printf("Quel verbe?\n");
scanf("%s", string);
RacineVerbe(string, racine);
printf("%s", racine);
printf("%sASSE\n", racine);
printf("%sASSES\n", racine);
printf("%sAT\n", racine);
printf("%sASSIONS\n", racine);
printf("%sASSIEZ\n", racine);
printf("%sASSENT\n", racine);
return 0;
}
void RacineVerbe(char verbeEntier[], char dest[]){
int i;
int l = myStrLen(verbeEntier);
for( i = 0; i < l -2 ; i++){
dest[i] = verbeEntier[i];
}
dest[i+1] = "\0";
}
int myStrLen(char *s){
int i = 0;
while(*s++)i++;
return i;
}

The problem is in you RacineVerbe because you assigned string literal to single character (not a poitner to characters).
In that situation, string literal returns you the address where it is in memory and you assigned to dest[i+i] LSB byte of that address and it may be or may not be visible character. I can assure, your compiler gave you at least warning for that.
Second problem is where you did assignment. You should do it to dest[i] as i was last time incremented in for loop before check failed and therefore i already points to place where 0 should be written.
void RacineVerbe(char verbeEntier[], char dest[]){
int i;
int l = myStrLen(verbeEntier);
for( i = 0; i < l -2 ; i++){
dest[i] = verbeEntier[i];
}
dest[i] = 0; //This line was rewritten.
}
And as already mentioned, try to NOT cast return result of malloc.

You invoked UB when you wrote dest[i+1] = "\0"; since dest[i+1] expects a char and you assigned "\0" into it, which is a string literal. Replace it with '\0'
Note that string = (char*)malloc(200*sizeof(char)); ---> string = malloc(200); since casting is not needed in malloc in C, and considered bad (as you can see here) and also sizeof(char) is, by definition, 1

Related

Why does calling a function in a different order cause a segmentation fault in C?

I am working on a program in C that processes an array of character pointers. I have several functions that operate on this array, including longest_name(), unique(), and others. When I call the longest_name() function after unique() in the main() function, the program runs fine. But when I switch the order and call longest_name() before unique(), I get a segmentation fault.
I know that the pointer char *name in the longest_name() function should be allocated by malloc to avoid the segmentation fault. However, I want to understand why the program is working in one scenario but not in the other.
My suspicion is that the issue may be related to memory allocation or pointer manipulation, but I am not sure where to start looking. Can anyone explain why this is happening and how to fix it?
#include <stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
void display_name(char **stu, int indx);
void vowel_count(char **stu, int indx);
void longest_name(char **stu);
void unique(char **stu);
int main()
{
char *name[10] = {"Aakash", "Anirudha", "Vikas", "Vinay", "Rakesh", "Thomas", "Jerry", "Alekha", "Daksh", "Peter"};
display_name(name, 4);
vowel_count(name,9);
//longest_name(name); //not run
unique(name);
longest_name(name); //run
return 0;
}
void unique(char **stu){
int len = 0, found = 0;
printf("Name whose first and last character is \'a\' :- ");
for(int i = 0; i < 10; i++){
len = strlen(stu[i]);
if(stu[i][0] == 'a' && stu[i][0] == 'a'){
found = 1;
printf("%s\n", stu[i]);
}
}
if(found == 0){
printf("None\n");
}
}
void longest_name(char **stu){
int len = 0, mx = 0;
char *name;
printf("\n Address is %p \n",name);
for(int i = 0; i < 10; i++){
if(mx < strlen(stu[i])){
mx = strlen(stu[i]);
strcpy(name, stu[i]);
}
}
printf("Longest name is \"%s\" with length %d\n", name, mx);
}
void vowel_count(char **stu, int indx){
indx--;
for(int i = 0; i < 10; i++){
if(i == indx){
int len = strlen(stu[i]), cnt = 0;
char name[len];
strcpy(name, stu[i]);
for(int j = 0; j < len; j++){
char c = tolower(name[j]);
if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
cnt++;
}
printf("Number of vowels in \"%s\" are :- %d\n", name, cnt);
break;
}
}
}
void display_name(char **stu, int indx){
indx--;
for(int i = 0; i < 10; i++){
if(i == indx)
printf("%s\n",stu[i]);
}
}
I tried running the program on a different machine as I thought the issue might be related to the compiler. However, the behavior was the same on the other machine as well.
As mentioned in the comments, your variable name in your longest_name function is uninitialised.
You have declared it like this:
char *name;
and have not made it point anywhere.
Many compilers will manually initialise the pointer to zero, such as having written:
char *name = NULL;
... but this is not guaranteed, so it is good practice to always initialise your pointers to NULL if you do not wish to make them point anywhere yet. Nonetheless, it is important to note that initialising to NULL just means the pointer definitely does not point anywhere.
In your case, it looks like your name pointer might have been initialised to some random value - such as whetever was at that location on the stack previously. If the latter is the case, it would explain why your program works sometimes, and at other times it does not. As mentioned by a comment, the order with which you call the functions will determine what is on the stack (beneath the stack pointer) by the time the second function is called. Thus, it is perfectly plausible that when you call your unique function first and THEN your longest_name function, by sheer luck your name variable in your longest_name function is initialised to some "valid" memory location, which means you are able to write data to it.
What is happening is described as undefined behaviour. Essentially, this means that your program can sometimes perform as you expected, and sometimes do something completely different. Undefined behaviour happens when something in the program has not been written correctly, but that does not necessarily always make the program crash instantly. However, if you write a program correctly, you can avoid UB (undefined behaviour) completely.
Thus, you should never do something like:
char *whatever = "It was a sunny day.";
char *str;
strcpy(str, whatever);
... because you have not made the pointer str point anywhere valid, and you cannot copy data to a memory location that does not exist or one that cannot be accessed by your program.
In your case, your longest_name function should allocate memory and make the name pointer point to this allocated memory, before copying anything to it, such as:
name = malloc((strlen(stu[i]) + 1)*sizeof(char));
strcpy(name, stu[i]);
... remembering to free the memory after using it.
Remember, a string stored as a char* always needs to include an extra byte for the null terminator character '\0' or simply 0 in ASCII. This is where you have gone wrong in your vowel_count function, your declaration of name should be:
char name[len + 1];
Note also that by declaring name like that you are declaring a variable-length array (VLA), which can be tricky. If you need memory with a dynamic size (determined at runtime) it is usually better to use dynamic memory allocation (using malloc, and free for deallocation).
Furthermore, in your longest_name function, you don't need to allocate any extra memory, all you need is to make your name pointer point to the longest string, and print that out, such as:
void longest_name(char **stu){
size_t len = 0, mx = 0; // strlen returns a number of type size_t
char *name = NULL; // initialise to NULL since not pointing anywhere
printf("\n Address is %p\n", name); // this will either be zero or undefined
for(unsigned int i = 0; i < 10; i++){ // use unsigned as you start from zero
if(mx < (len = strlen(stu[i]))){ // assign len to only call strlen once
mx = len;
name = stu[i]; // simply make name point to the longest string
}
}
printf("Longest name is \"%s\" with length %zu\n", name, mx);
}
In conclusion, your program runs sometimes and at other times it crashes, becuase your name variable sometimes ends up pointing somewhere "valid", and sometimes it doesn't. You can fix this by always ensuring your pointers point somewhere valid before using them.

The below code runs encryption part well but when 'z' is entered it gives unexpected output and doesnt run decryption part

#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(;i<100;i++)
{
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(;i<100;i++)
{
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
You are returning a pointer to automatic variables en and de which are stored in the stack. This in turn means after returning from the functions encrypt and decrypt their place in the memory can be used by any other variable.
so to correct that, you need to define en and de as static.
const char *encrypt(char *str){
static char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1){
static char de[100];
int i=0;
for(;i<100;i++){
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
Though a more suitable and safer way to implement that would be:
#include<stdio.h>
void encrypt(char *str, char *encStr);
void decrypt(char *str1, char* decStr);
int main()
{
char str[100], encDecStr[100];
//Encryption
printf("Enter String for encryption\n");
scanf("%s", str);
encrypt(str, encDecStr);
printf("%s after encryption is %s\n",str,encDecStr);
//Decryption
printf("Enter String for decryption\n");
scanf("%s", str);
decrypt(str, encDecStr);
printf("%s after decryption is %s",str,encDecStr);
return 0;
}
void encrypt(char *str, char *encStr)
{
for(char *c = str; *c != '\0'; c++)
{
*encStr++ = *c + 1;
}
*encStr='\0';
}
void decrypt(char *str1, char* decStr)
{
for(char *c = str1; *c != '\0'; c++)
{
*decStr++ = *c - 1;
}
*decStr++='\0';
}
Note: The code was not fully tested for different use cases.
There are quite a number of errors in your code:
Returning arrays with local storage duration:
The array's life time ends (i.e. it ceases to exist) as soon as you exit from the function, thus the pointer returned is dangling, reading from it is undefined behaviour
You write beyond the bounds of your local array: en[i] = '\0' with i being 100 after the loop is out of the range of valid indices from 0 to 99, which again is undefined behaviour.
You have differing offsets for encrypting (1) and decrypting (3).
Simply adding an offset without further checks (or modulo operations) will produce different character sets for input and output strings (might be your least problem...).
You always en-/decode the entire array, which is more than actually needed. Additionally the terminating null character then is encoded as well, resulting in different lengths of input and output and garbage at the end of encoded string.
Use of gets is dangerous as it allows a user to write beyond the input array, resulting in undefined behaviour. This is the reason why it actually has been removed from C language with C11 standard – which introduces a safe alternative gets_s. Yet another alternative (especially for pre-C11 code) is fgets.
For the dangling pointer problem there are several options:
Making the array static (as mentioned already):The disadvantage of this approach is that the function is not thread-safe any more. Additionally calling the function more than once overwrites previous results, if you haven't evaluated already or copied them they are lost.
Returning a dynamically allocated array, see malloc function. This comes with the risk of the caller forgetting to free the allocated memory again, which would result in a memory leak
Changing the input array in place: Disadvantage of is having to copy the input into a backup if it is yet needed afterwards.
Letting the caller provide the buffer.
Last option is most flexible and most idiomatic one, so I'll concentrate on this one:
void caesar(char const* input, char* output, int offset)
{
int const NumChars = 'z' - 'a';
offset = offset % NumChars + NumChars;
// ^ assures valid range, can still be negative
// ^ assures positive value, possibly
// out of range, but will be fixed later
for(;*input; ++input, ++output)
{
int c = *input - 'a';
// distance from character a
c = (c + offset) % NumChars;
// ^ fixes too large offset
*output = 'a' + c;
}
// as now iterating *until* null character found we now *need*
// to add it (in contrast to original version with whole array!)
*output = 0;
}
This variant includes an interesting idea: Let the caller define the offset to be applied! The modulo operation assures the valid range of the character, no matter how large the offset is. The great thing about: If a user encoded with some number n, exactly the same function can be used to decode again with -n (which is why I simply named it caesar according to the algorithm it implements). Note that this is untested code; if you find a bug please fix yourself...
Be aware, though, that this code still has two weaknesses:
It assumes ASCII encoding or compatible – at least one where letters a to z are in contiguous range, a is first character, z is last one. This is not true for all encodings, though, consider the (in-?)famous EBCDIC.
It assumes all input is in range of Latin minuscules only (from a - z), it does not consider white-space, digits, capital letters, punctuation marks... You might want to include special handling for all of these or at least the ones you might use.
You could fix these e.g. (many other variants are thinkable as well) by
converting all characters to either upper or lower case (toupper((unsigned char)*input) – assuming case doesn't matter)
search in an array of valid characters ("ABC...XYZ012...89") for the appropriate index and if found encode like above with NumChars being array length, otherwise (whitespace, punctuation) just leave as is.
In any case, the function would then be called like:
char input[128]; // prefer powers of 2 for array lengths...
char en[sizeof(input)];
char de[sizeof(input)];
gets_s(input, sizeof(input));
caesar(input, en, 7);
// en contains encrypted string, could e.g. be printed now
caesar(en, de, -7);
// de contains decrypted string
// you could even encode/decode in place:
caesar(input, input, 7);
// just be aware that this will fail, though, for the case if input
// and output overlap and input starts before output, as then at
// some point already encoded values will be read as input again:
// caesar(input, input + 1, 7) fails!!!
There's some issues in your code :
Not a very big issue for a beginner , but you should avoid gets function.
Because it doesn't check the input , it can cause buffers overflow and various security problems , try using fgets instead.
In encrypt , and decrypt functions , you are returning the address of an array located in the stack of the function , look :
const char *encrypt(char *str){
char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
Here , Since the en array is declared inside the function , after the return you may get garbage string when trying to read it.
The solution here , is to either malloc it , or declare a static array outside the function , and initialize it.
You are encrypting by adding 1 to the value of the string , and decrypt it by retrieving 3 . I don't know if this is what you intended to do.
Here's a new version of your code , try to check if it suits your need :
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
static char de[100] , en[100] ;
const char *decrypt(char *str1){
memset(de , 0 , 100) ;
int i=0;
for(;i<strlen(str1);i++){
de[i]=str1[i]-1;
}
de[i]='\0';
return (const char*) de;
}
const char* encrypt(char* str){
memset(en , 0 , 100) ;
int i=0;
for(;i<strlen(str);i++){
en[i]=str[i]+1;
}
en[i]='\0';
return (const char*) en;
}
int main(){
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
Your code does not handle a special case for the character 'z'. Thus
en[i]=str[i]+1;
Causes the character '{' to be written to the array en instead. For learning more about why this happens, I recommend you look at ASCII tables and looking at the integer values for alphabets.
Secondly, did you mean to type -3 in there?
de[i]=str1[i]-3;
This won't work if you're planning on using the decrypt() function to decrypt strings that you made using encrypt() because you're adding 1 to the character while encrypting and then subtracting a different number when decrypting, so the result will appear garbled.
I rewrote your code for you, since this is a beginner program, I made as little changes as possible so you can understand it. I WOULD HIGHLY RECOMMEND NOT USING gets() though... See here.
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
encrypt(str);
printf("%s after encryption is %s\n", str, encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
decrypt(str1);
printf("%s after decryption is %s", str1, decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'z')
{
en[i] = 'a';
continue;
}
en[i] = str[i] + 1;
}
en[i] = '\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'a')
{
en[i] = 'z';
continue;
}
de[i] = str1[i] - 1;
}
de[i] = '\0';
return de;
}
Some criticisms
Like I said, gets() is really bad... See here for more details. Although it might be too complicated for you... A better alternative is fgets!
fgets(str, num, stdin)
takes user input from the console, and then stores it inside the array str, which must be large enough to store at least num characters. Don't worry about stdin if you don't know what that means. But be sure to always write it when using fgets as an alternative to gets
Like others have already posted, albeit using more technical jargon, it's a bad idea to declare an array inside a function and then return that array. You know the function ends when the return statement is hit, and at that point all the variables that were declared inside the function will get destroyed.
That doesn't necessarily mean that you can't read the data that was in them, but it becomes a probabilistic game where there's a teeny-tiny chance that the array will get corrupted after the function exits and before the data in that array is read. This is technically Undefined Behaviour.
I hope you know about pointers. You can modify the array which you passed as a parameter directly and then return that array, thus avoiding accessing an array outside it's lifetime.

The following C code outputs a segmentation fault error which I can hardly understand why

#include <stdio.h>
void append(char* s, char n);
void splitstr(char* string);
int main()
{
splitstr("COMPUTE 1-1");
printf("\n");
splitstr("COMPUTE 1+1");
printf("\n");
splitstr("COMPUTE 1*1");
return 0;
}
void append(char* s, char ch) {
while(*s != '\0'){
s = s + 1;
}
*s = ch;
s = s + 1;
*s = '\0';
}
void splitstr(char* string){
int count = 1;
char* expression = "";
while(*string != '\0'){
if(count > 8){
append(expression, *string);
string = string + 1;
count = count + 1;
}else{
string = string + 1;
count = count + 1;
}
}
printf("%s",expression);
}
Example Input and Output:
Input: COMPUTE 1+1
Output: 1+1
Input: COMPUTE 2-6
Output: 2-6
Originally, this code does not include stdio.h (I am doing this for testing on an online C compiler) because I am building an OS from scratch so I need to write all the functions by myself. I think the problem might be in the append function but I cannot find it.
instead of
char* expression = "";
do
char[MAX_expression_length+1] expression;
or use realloc in the append function
I think this line is the culprit:
append(expression, *string);
Notice how expression is declared:
char* expression = "";
In other words, expression consists of one byte, a single \0. Right away, we can see that append() won't work like you want it to--the while loop will never run, because *s is already \0.
But beyond that, the segfault likely happens at the bottom of append(). After the while loop, you unconditionally increment s and then write to the location it now points to. The problem is that this is a location that has never been allocated (since s is a reference to splitstr()'s expression, which is a single byte long). Furthermore, because expression is declared as a string constant, depending on your platform it may be placed in an area of memory marked read-only. Consequently, this is an attempt to write into memory that may not actually belong to the process and may also not be writable, raising the fault.
expression points to a string literal, and trying to modify a string literal leads to undefined behavior.
You need to define expression as an array of char large enough to store your final result:
char expression[strlen(string)+1]; // VLA
Since your result isn’t going to be any longer than the source string, this should be sufficient (provided your implementation supports VLAs).

An error caused by "a WRITE memory access"

tbh I thought it wouldn't be hard to learn C seeing as I already know several other languages, but I'm having trouble with my code, and I can't seem to figure out how to fix these errors. I specialize in Python, so this is much different because of all the specifications for types, pointers, etc. Anyway, here's the code below, sorry, I would paste the error, but it won't allow me to copy paste. I was using some print functions and found the error to be coming from line 9, "*returnStr += *str";. Thanks in advance for any help.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
char *multiplyString(const char *str, int num){
char *returnStr = "";
for (int i = 0; i < num; i++){
*returnStr += *str;
}
return returnStr;
}
int main(void){
bool asking = true;
int height;
const char *symbol = "#";
while (asking == true){
height = get_int("How tall should the pyramid be? pick a number between 1 and 8: ");
if (8 >= height && height >= 1){
asking = false;
}
}
for (int i=1; i<=height; i++){
printf("%s %s\n", strcat(multiplyString(" ", height-i), multiplyString(symbol, i)), multiplyString(symbol, i));
}
}
Change multiplyString() to the following
char *multiplyString(const char *str, int num) {
// + 1 for null-terminator
char *returnStr = calloc(sizeof(*returnStr), strlen(str)*num + 1);
for (int i = 0; i < num; i++) {
strcat(returnStr, str);
}
return returnStr;
}
You were attempting to modify a string literal, which is forbidden in C. Secondly, += is not string concatenation in C; rather, it was trying to perform integer addition on the first character of returnStr.
To fix this, you dynamically allocate the proper amount of memory using calloc() (which also initializes the memory to 0, which is necessary for strcat()). Then, in each iteration, append the string using strcat() to the end of the new string.
Remember to free the strings returned by this function later in the program, as they are dynamically allocated.
Two problems:
First of all, returnStr is pointing to a string literal, which is really an array of read only characters. In this case an array of only a single character, being the string terminator '\0'
Secondly, *returnStr += *str; makes no sense. It's the same as returnStr[0] = returnStr[0] + str[0]. And since the destination (returnStr[0]) is a string literal, attempting to write to it leads to undefined behavior
If you want to create a new string containing num copies of str, then you need to create a new string containing at least num * strlen(str) + 1 characters, the +1 for the terminator. Then you need to use strcat to concatenate into that new string.
Also if you allocate memory dynamically (with e.g. malloc) then you need to make sure that the first element is initialized to the string terminator.

C error: Exited with non-zero status

I know this code is quite simple; but that message won't stop appearing, can you help me find where the error is?
#include <stdio.h>
void Reverse(char * word[]) {
char temp = word[0];
for (int i = sizeof(word); i >= 0; i--){
for (int j = 0; j<= sizeof(word); j ++){
word[0] = word[i];
}
}
word[sizeof(word)] = temp;
printf("%s", word);
}
void main() {
Reverse(gets(stdin));
return 0;
}
gets returns char*. In this context - It is wrong to write char *[] in the function definition where you are supposedly passing a char array where input characters are being stored using gets. Also char *gets(char *str) - you need to pass a buffer to the gets where the inputted letters will be stored. You didn't pass one.
sizeof doesn't work here. It returns the size of a pointer (char*). You will have to use strlen() to get the length of the string inputted by gets.
More importantly - don't use gets - it's time to use something much safer than gets, namely fgets etc. Buffer overflow is not something you want to deal with.
Suppose you are passing an array of char* to the function reverse. Then the parameter would be char*[] which means nothing other than char** here. Here you will simply pass the char array which you will be using as buffer to gets.

Resources