Why does this program give me a "segmentation fault"? - c

So my brother was making a program to turn all words in a string to hashtag, but for some reason it always gives a "segmentation fault" error at the end of execution. I tried to find what may cause it, but haven't found. Here's the code:
#include <stdio.h>
#include <string.h>
char* setHashtag(char text[10000])
{
int i, j;
printf("Initial text = %s\n", text);
for (i = 9998; i >= 0; i--)
{
text[i+1] = text[i];
}
text[0] = ' ';
for (i = 0; text[i+1] != '\0'; i++)
{
if(text[i] == ' ' && text[i+1] != ' ')
{
for (j = 9998; j > i; j--)
{
text[j+1] = text[j];
}
text[i+1] = '#';
printf("Partial text = %s\n", text);
}
}
return text;
}
void execute() {
char text[5000], textFinal[10000];
gets(text);
strcpy(textFinal, setHashtag(text));
printf("%s\n", textFinal);
}
int main()
{
execute();
printf("Back to main\n");
return 0;
}

You pass an array of size 5000 into your function, yet you access 10000 elements inside. Of course, it will crash.
This size of the array specified in function declaration does not matter. It is ignored by the compiler. This
char* setHashtag(char text[10000])
is equivalent to this
char* setHashtag(char *text)
i.e. the function receives a pointer to the beginning of your original argument array, not a new local copy of the argument array (naked arrays in C are not copyable).
This means that when you call your function as
char text[5000];
...
setHashtag(text)
the text array does not magically become a char [10000] array. It remains a char [5000] array, as it was originally declared. Attempting to access text[9998] and such inside the function leads to undefined behavior.
Since your setHashtag function expects a fixed size array of size 10000, it might be a better idea to declare your function as
char* setHashtag(char (*text)[10000])
and pass in the array arguments as setHashing(&text). This will make sure you will not be able to pass in an array of wrong size. Inside the function you'll have to access the array as (*text)[i].

Related

Passing char by reference

The problem is that I am trying to pass a sentence by reference to change something about it(this case adding a character), but nothing is changed.
The first thing I tried was this original code but without putting in any "*" or "&" and I got the same output. I have read other similar questions that have used strcpy() but I am not sure how that might apply to this problem or what the solution might be as I am unfamiliar with pointers used in this way.
char my_char_func(char *x)
{
return x+'c';
}
int main()
{
char (*foo)(char);
foo = &my_char_func;
char word[]="print this out";
puts(word);
foo(&word);
puts(word);
return 0;
}
I am expecting the second output to be "print this outc"
You're adding the character c to the actual pointer. As you can't dynamically expand your character array in C, I believe you're going to have to malloc a new array with space for the extra character, delete the pointer being passed in, and then set it the beginning of the new array. That should avoid memory overrun.
int main()
{
char (*foo)(char);
int i = 0;
foo = &my_char_func;
char word[]="print this out";
for(i = 0; i < size_of(word); ++i)
{
word[i] = toupper(word[i]);
}
puts(word);
foo(&word);
puts(word);
return 0;
}
If you don't want to use toUpper, you can change you function in either of two ways:
Option 1:
void my_char_func(char *string, int sizeOfString)
{
int i = 0;
for(i = 0; i < sizeOfString; ++i)
{
//Insert logic here for checking if character needs capitalization
string[i] = string[i] + ' ';
}
}
Option 2:
Do the same as with toUpper, simply calling your own function instead.

Program returns -1073741819 when using strcat in C

This is the whole function. Basically what I was trying to do is to erase some words from a sentence. I experience when the program reaches the first strcat line.
I really have no clue, what is the problem here? Did I misuse the pointers?
EDIT: I try this:
void reset_array(char* word,int n)
{
for (int i = 0; i < n; i++)
word[i] = 0;
}
void change_sentence(char* new_sentence, char* sentence, int n)
{
while (new_sentence!=EMPTY)
{
*sentence = *new_sentence;
sentence++; new_sentence++;
}
}
void delete_words(char * words[], int n, char * sentence)
{
char* sen_copy = sentence; bool first = true;
char* new_sentence = (char*)malloc(sizeof(char)*strlen(sentence)+1);
reset_array(new_sentence, strlen(sentence) + 1);
char* new_sentence_copy = new_sentence;
while (*sen_copy)
{
char current_word[MAX_LEN];
reset_array(current_word,MAX_LEN);
int i = 0;
while (*sen_copy && *sen_copy != WORD_SEPERATOR)
{
current_word[i] = *sen_copy;
i++;
sen_copy++;
}
if (!is_string_in_array(words, n, current_word))
{
if (!first)
{
*new_sentence_copy = WORD_SEPERATOR;
new_sentence_copy++;
}
int count = 0;
while (count < i)
{
*new_sentence_copy = current_word[count];
count++;
new_sentence_copy++;
}
first = false;
}
if (*sen_copy == WORD_SEPERATOR)
sen_copy++;
}
printf("Hi");
change_sentence(new_sentence, sentence, strlen(sentence) + 1);
free(new_sentence);
}
I get the same error code.
What causes the error now? Am I not allowed to change sentence? I thought you could do it if it's an array.
From the C Standard, § 6.7.9: Initialization:
The declaration char *p = "abc"; defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’ with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
Emphasis mine.
You cannot assign to new_empty_string after it is declared. Neither the assignment operator, =, nor making it the destination parameter in strcat will work. Your options:
Declare new_empty_string as an array of type char [], where the length is sufficient to hold the value(s) you expect
Allocate sufficient memory for new_empty_string with malloc or related functions, and free the memory when you are done using it.

c function convert "fffoootoo" to "foto" (leaves out following repeating characters)

The task would be to remove following characters that are repeating from a char array, like "deeeciddeee" -> "decide" or "phhhonne" -> "phone".
I have a function that crashes the console, and I can't spot the bug:
char* my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
}
}
return ret;
}
it is called this way:
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
please help me!
Besides a small bug (you should add the line i--; after last--;, because you're deleting the character at possition i, so what has been the character at i+1 became the new character at possition i. If you don't decrease i, it will be increased and you jump over a character) the code runs perfectly fine IF it is called with
const char* b = "oooat";
char* a = new char[strlen(b) + 1];
for (size_t c = 0; c < strlen(a) + 1; c++) { a[c] = b[c]; }
a = my_unique(a, a + strlen(a));
cout << a;
delete[] a;
Notice that I've used a edit-able copy of the string, as the literal itself is of type const char* and therefor can't be changed at all. And as I said, this works perfectly fine and prints "oat", just as expected, without any crash. So your problem might be that you try to edit a const string literal? In that case you might consider to copy it, as I did, or use std::string (if you code in C++).
There are many beginner mistakes in the code.
Let me point you one by one.
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
When you declare a string like this : char* a="oooat", a is a string literal. The memory for the string is allocated into text section of the program. Which basically means you cannot modify the values inside the strings. You can only read from them. Hence when you are passing pointer a to the function and modifying it, it will result in segmentation fault(Illegal access to memory).
Why do you need a ret pointer here? char* ret=first;
You are passing a pointer and modifying the value inside it. Hence the new data will be reflected in the calling function and we need not return it explicitly. So, it is redundant.
Overall logic can be simplified as well
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MYSTR "ooooat"
void my_unique(char *first, char *last) {
int size = last - first;
int i = 0, j = 0, k = 0;
for (; i < size; i++, j++) {
first[j] = first[i];
// Continue to check how many repetitions are there
while (i + 1 < size && (first[i] == first[i+1])) i++;
}
// In the end terminate the string with a NULL.
first[j] = '\0';
return;
}
int main()
{
char a[] = MYSTR;
my_unique(a, a+strlen(a));
printf("%s", a);
return 0;
}
This is in C. There are simpler ways of doing this in C++, and the code can definitely be condensed but has been left simpler for readability.
#include <stdlib.h>
char* fix(char *input) {
char *lookahead = input;
char *newchar, *ret;
// Determine Max Return String Length
int len = 0;
while (*lookahead != '\0') {
len++;
lookahead++;
};
// allocate max possible memory needed and set the pointers
ret = malloc(len);
newchar = ret;
lookahead = input;
*newchar = *lookahead; // copy the first character
while (*lookahead != 0) {
lookahead++; // incrementing this ptr first starts lookahead at 2nd character and
// ensures the null terminator gets copied before the while loop ends
if (*newchar != *lookahead) { // only copy new characters to new return string
newchar++;
*newchar = *lookahead;
};
};
return ret;
};
I'll try to give my answer so that it makes the as little changes as possible to your original code, while using the simplest methods.
The main problem has already been identified by the previous comments - you cannot alter a string literal.
Also, the line of code
i--;
has to be placed as well, with the reason well clarified above.
While making an editable version of the string may be a good way of fixing the problem, a more straightforward way would be to make it a local string, as such :
char b[] = "oooat";
but doing this will make it incompatible with the return type of your my_unique function (char*). But why would you need a return type in the first place, if you are fixing the string itself?
My final code would look like this :
void my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
i--;
}
}
}
making the function return void.
Hope this helps.

Pointers and local arrays in C

Why doesn't my function printTable print the content of my array? For example, from the whole word 'oui' stored in my array mysteryword it prints only 'o'?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#define libraryDimension 12
char* getFirstElementPointerOfMysteryWord(void);
char getCarac(void);
void printTable(char*ptr,int dimension);
/* Main program*/
int main() {
//getCarac();
char *pointerForFirstElement = getFirstElementPointerOfMysteryWord();
int tableDimension = 3;
printTable(pointerForFirstElement, tableDimension);
return 0;
}
This function is intended to provide a choice of words it has no parameters and it returns the address of the first element of my word's array.
char *getFirstElementPointerOfMysteryWord(void) {
int randomNumbers[3] = {0};
char mysteryWord[4];
char wordLibrary[libraryDimension];
wordLibrary[0] = '#';
wordLibrary[1] = 'n';
wordLibrary[2] = 'o';
wordLibrary[3] = 'n';
wordLibrary[4] = '#';
wordLibrary[5] = 'o';
wordLibrary[6] = 'u';
wordLibrary[7] = 'i';
wordLibrary[8] = '#';
wordLibrary[9] = 'q';
wordLibrary[10] = 'u';
wordLibrary[11] = 'i';
wordLibrary[12] = '\0';
int j=0;
for (int i = 0; i<libraryDimension; i++) {
if(wordLibrary[i] == '#') {
randomNumbers[j] = i;
j++;
}
}
srand(time(NULL));
int index = rand() % 3;
int randomNumber = randomNumbers[index];
int k=0;
for (int i = randomNumber ; i< libraryDimension-1 ; i++) {
if(wordLibrary[randomNumber+k+1] == '#'){
break;
}
else{
mysteryWord[k] = wordLibrary[randomNumber+1+k];
k++;
}
}
return mysteryWord;
}
This is the part where my code doesn't work properly.
void printTable(char *ptr,int dimension) {
for (int i = 0; i <dimension ; i++) {
printf("%c",*(ptr+i));
}
}
char getCarac(void){
char carac;
carac = getchar();
return carac;
}
When you declare a variable in a function, it is allocated on the stack. When the variable goes out of scope i.e. the function ends, the variable disappears (stack is local for the function) so by returning the address of the array you are returning an address that no longer exists.
Instead either allocate storage on the heap using malloc
char *mysteryWord = malloc(4);
or better, have it declared outside the function and then pass it to the function to fill.
void getFirstElementPointerOfMysteryWord(char* mysterword, size_t maxLen)
The problem is right here
char *getFirstElementPointerOfMysteryWord(void)
{
char mysteryWord[4];
/* other stuff */
return mysteryWord;
}
mysteryWord ceases to exist when the function returns. Any dereferencing of it by the caller (e.g. examining its content) or passing it to another function that dereferences (which your code does) gives undefined behaviour.
You need to ensure whatever pointer the caller receives, it continues to point at something that will exist for the caller. That can be done in various ways, each with different trade-offs. Probably the easiest is for the caller to PASS an array with 4 elements as an argument to this function (if the caller owns it, it will not cease to exist until the current scope within the caller ends)

C function to capitalize first letter of words in an array

I'm pretty new to C and am hitting a wall when creating the below function. I want to use this function to make the first letter of a word upper case for a static character array (char string[]. It looks ok to my eye, but I'm getting some syntax errors which are probably pretty basic.
compiler errors:
error: invalid conversion from const char' toconst char*'
initializing argument 1 of `size_t strlen(const char*)'
assignment of read-only location
void Cap(char string[]){
int i;
int x = strlen(string);
for (i=1;i<x;i++){
if (isalpha(string[i]) && string[i-1] == ' '){
// only first letters of a word.
string[i]= toupper(string[i]);
}if (isalpha(string[0]))
{
string[0]=toupper(string[0]);
}
}
}
you might want to run strlen(string) - as strlen(string[i]) is trying to get the length of a single char.
I will also point out your braces don't match ...
if (isalpha(string[i])){
string[i]= toupper(string[i]);
Remove brace on the if line or put a close brace after your assigning statement.
I took your code and tried to compile it. Well, it would be nice to see compilable code the next time. Here is one with comments.
#include <stdio.h> // Now I am able to use printf.
#include <string.h> // I was not able to use strlen without this...
void Cap(char string[]){
int i;
int x = strlen(string); // You want to get the length of the whole string.
for (i=1;i<x;i++){
if (isalpha(string[i]) && string[i-1] == ' '){
// only first letters of a word.
string[i]= toupper(string[i]);
}
}
}
main(){
char string[] = "text with lowercase words.";
Cap(string);
printf("%s",string);
};
Still the first word of the text is lowercase. This is a task for you.
You're missing the closing curly brace for your if statement. This might just be a typo in the question, but mentioning it just in case.
Your function is declared void. This means it returns nothing. Any return statement should have nothing after the word since the function returns nothing, and in many cases you won't have a return statement at all.
However, the biggest issue is that this isn't an array of strings. It's an array of chars, which is just one string. char* string and char string[] both (potentially) refer to an array of characters, which makes up a single string. You would need to use another level of indirection to refer to an array of array of characters: char** strings, char* strings[], or char strings[][]. The last form would require you specify how long all the strings could be, so you'd usually only use the first two.
The problem here is that you are passing in a single string, not an array of strings.
Basically in C, a string is an array of chars, hence an array of strings is a two dimensional array like so:
const char* strings[];
There are a few other issues with the code. You haven't initialized i before using it.
A alternate approach: (write a function)
1) (optional) Allocate memory for new buffer of same length for results in calling function.
2) In function - Set first char of new string to upper case version of original string
3) Walk through the string searching for spaces.
4) For each space, Set next char of new string to upper case of char in original string
5) Loop on 4) until NULL detected
6) Free any allocated memory in calling program.
Code example:
void capitalize(char *str, char *new)
{
int i=0;
new[i] = toupper(str[0]);//first char to upper case
i++;//increment after every look
while(str[i] != '\0')
{
if(isspace(str[i]))
{
new[i] = str[i];
new[i+1] = toupper(str[i+1]);//set char after space to upper case
i+=2;//look twice, increment twice
}
else
{
new[i] = str[i];//for no-space-found, just copy char to new string
i++;//increment after every look
}
}
}
This should work just fine.
#include <stdio.h>
#include <string.h>
capital(char s[])
{
int i;
for(i=0; i<strlen(s); i++)
{
if (i==0||s[i-1]==' '&&s[i]>='a'&&s[i]<='z')
s[i]=toupper(s[i]);
}
puts(s);
}
main()
{
char s[100];
printf("Enter a line: ");
gets(s);
capital(s);
}
I made an update based on Stefan Bollmann answer:
#include <string.h>
#include <stdio.h>
char* uc_words(char string[])
{
int i;
int x = strlen(string);
int counter = 0;
for (i = 0; i < x; i++)
{
// If found a white-space reset counter
if (isspace(string[i]))
counter = 0;
// Check if first character in word
if (isalpha(string[i]) && !isspace(string[i]) && counter == 0)
{
string[i]= toupper(string[i]);
counter = 1;
}
}
return string;
}
int main()
{
char string[] = "hello world";
printf("%s\n", uc_words(string));
return 0;
}

Resources