This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 5 years ago.
So this is supposed to be a concordance program where it grabs words from a text file. I'm trying to use a struct to store the string, and also the number of times the word occurs in the text file. I also want to place the struct object into an array of structs, because I will need to sort the words alphabetically once I have them all. However, I'm getting a segmentation fault inside my createStruct function. I know the problem is with my limited knowledge of pointers and passing by reference. I've been messing with createStruct and compareStruct for days now and it just isn't clicking.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct word{
char *wordArr;
int wordCount;
}word;
char *makeLowerCase(char word[]);
char *removeFirstChar(char word[]);
char *removeLastChar(char word[]);
void createStruct(struct word wordObj, char word[]);
void structCompare(struct word wordObj, struct word objArr[]);
int main(int argc, char * argv []) {
char buff[] ="##Hello$$$$$"; //hard coded, will grab words from a .txt file
struct word newWord = {.wordArr = NULL, .wordCount = 0};
struct word structArray[500];
makeLowerCase(buff);
removeFirstChar(buff);
removeLastChar(buff);
createStruct(newWord, buff);
structCompare(newWord, structArray);
//trying to print from the array
printf("%s %d", structArray->wordArr, structArray->wordCount);
return 0;
}
char *makeLowerCase(char grabbedWord[]) {
int i;
size_t wordLength = strlen(grabbedWord);
for(i = 0; i < wordLength; i++) {
grabbedWord[i] = tolower(grabbedWord[i]);
}
return grabbedWord;
};
char *removeFirstChar(char inputWord[]) {
int i = 0;
size_t length = strlen(inputWord);
if (!isalnum(inputWord[i])) {
i++;
strncpy(inputWord, &inputWord[i], length);
return removeFirstChar(inputWord);
}
return inputWord;
};
char *removeLastChar(char inputWord[]) {
size_t length = strlen(inputWord);
if (!isalnum(inputWord[length - 1])) {
inputWord[length - 1] = 0;
return removeLastChar(inputWord);
}
return inputWord;
};
void createStruct(struct word wordObj, char string[]) {
strcpy(wordObj.wordArr, string);
wordObj.wordCount = 1;
};
void structCompare(struct word obj, struct word structArr[]) {
int i;
for(i = 0; i < sizeof(structArr); i++) {
if(structArr[i].wordCount == 0) {
strcpy(structArr[i].wordArr, obj.wordArr);
structArr[i].wordCount = obj.wordCount;
}
else if(strcmp(structArr[i].wordArr, obj.wordArr) == 0) {
structArr->wordCount++;
}
else {
strcpy(structArr[i].wordArr, obj.wordArr);
structArr[i].wordCount = obj.wordCount;
}
}
};
You get a segmentation fault because of a NULL pointer.
For copying a string, you use strcpy(char *dest, char *src). But the dest needs to be allocated. In your case, is just NULL;
So this is what you need to do:
// Add a \0 to the end of a string so you know when to stop.
char buff[] ="##Hello$$$$$\0";
// Allocate the char array so you know where to copy it. I allocate it by default to 500, change this based on your needs.
struct word newWord = {.wordArr = (char *)malloc(sizeof(char) * 500), .wordCount = 0};
If you pass the struct to a function directly, you will pass a copy of it so any change done in the function, will not be seen outside of the function. So you need to pass a pointer to the struct instead of the actual struct.
Related
I have a structure inside which char array and int value is maintained. I want to treat this char array as a flat array to store the list of strings and the offset will track the starting position where the string is added in the array.
Structure is shown below:
struct A
{
char element[256];
int offset;
}
Also, I want to delete the strings after performing some operation if found.
Please let me know if this feasible. If yes then how?
Yes, append to a.element[a.offset].
To delete, set a.element[0] to the null byte. C strings end at a null byte.
#include <stdio.h>
#include <string.h>
typedef struct
{
char element[256];
int offset;
} A;
void A_append(A* a, const char *str) {
// Concatenate on the end of element.
strcat(&a->element[a->offset], str);
// Increment the offset to the new end.
a->offset += strlen(str);
}
void A_delete(A* a) {
a->element[0] = '\0';
a->offset = 0;
}
int main() {
A a = { .element = "" };
a.offset = 0;
char string1[] = "one";
A_append(&a, string1);
char string2[] = "two";
A_append(&a, string2);
puts(a.element);
A_delete(&a);
puts(a.element);
}
You can also store a pointer to the end of element. It's the same thing, just more direct.
#include <stdio.h>
#include <string.h>
typedef struct
{
char element[256];
char *end;
} A;
void A_append(A* a, const char *str) {
// Concatenate nto the end of element.
strcat(a->end, str);
// Increment the pointer to the new end.
a->end += strlen(str);
}
void A_delete(A* a) {
a->element[0] = '\0';
a->end = a->element;
}
int main() {
A a = { .element = "" };
a.end = a.element;
char string1[] = "one";
A_append(&a, string1);
char string2[] = "two";
A_append(&a, string2);
puts(a.element);
A_delete(&a);
puts(a.element);
}
Finally, if you want to store a list of strings, not concatenate them, consider storing them as pointers.
Since all we have to go on is the question if it's feasible - and the answer is yes. Here's a way showing that it is:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct A A;
struct A {
char element[256];
int offset;
};
A *A_create() {
A *a = malloc(sizeof *a);
a->offset = 0;
return a;
}
void A_destroy(A *a) {
free(a);
}
// return false if the string doesn't fit
// true if it's successfully added
bool A_add_string(A *a, const char *str) {
size_t len = strlen(str);
if(a->offset + len >= sizeof a->element) return false;
memcpy(a->element + a->offset, str, len + 1);
a->offset += len + 1;
return true;
}
You can now create an A, add \0 terminated strings to it and finally destroy it:
A *a = A_create();
A_add_string(a, "Hello");
A_add_string(a, "world");
A_destroy(a);
This question already has answers here:
Why is this string reversal C code causing a segmentation fault? [duplicate]
(8 answers)
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 2 years ago.
int length(char *);
char* reverse(char *);
int main()
{
int a;
char p;
a=length("Computer");
printf("%d", a);
printf("\nReverse : %s", reverse("Computer"));
getch();
return 0;
}
int length(char *p)
{
int i;
for(i=0;*(p+i)!='\0'; i++);
return(i);
}
char* reverse(char *p)
{
int len, i;
char temp;
for(len=0; *(p+len)!='\0'; len++);
for(i=0; i<len/2; i++)
{
temp=*(p+i);
*(p+i)=*(p+len-1-i);
*(p+len-1-i)=temp;
}
return(p);
}
I am trying to print the length of the string inputted without using strlen() function and also creating a user defined function using pointer and function to reverse a string without using strrev() function. After compilation the program doesn't throws an error but it just does not display anything. The length is being printed correctly but the reverse section is not being printed and I can't figure out why? Help me out here people.
first of all, as user3121023 said, string constants (or literals) cannot be modified.
The problem was with indexes, pointer and at the end the piece of code that reverse the string. I adjust it in certain points and I'm gonna attach you here:
#include <stdio.h>
#include <stdlib.h>
int length(char *);
char * reverseWithDynamicMemory(char *, int);
char * reverseWithoutDynamicMemory(char *, int, char *);
int main() {
char *pWord = "Computer";
int wordLength = length(pWord);
char reverseWordWithouDynamicMemory[wordLength];
printf("Word Lenght: %d\n", wordLength);
printf("\nReverse with Dynamic Memory: %s\n", reverseWithDynamicMemory(pWord, wordLength));
printf("Reverse without Dynamic Memory: %s\n\n", reverseWithoutDynamicMemory(pWord, wordLength, reverseWordWithouDynamicMemory));
return 0;
}
int length(char *pWord) {
int i;
for (i = 0; *(pWord + i) != '\0'; i++);
return i;
}
char * reverseWithDynamicMemory(char *pWord, int length) {
int i = 0, end = length - 1;
char *reverseWord = (char *) malloc(sizeof(char) * length);
if(!reverseWord) {
printf("\nError allocating memory for reverseWord...\n");
exit(EXIT_FAILURE);
}
while (i < end || end >= 0) {
reverseWord[i] = pWord[end];
end--;
i++;
}
reverseWord[length] = '\0';
return reverseWord;
}
char * reverseWithoutDynamicMemory(char *pWord, int length, char *reverseWord) {
int i = 0, end = length - 1;
while (i < end || end >= 0) {
reverseWord[i] = pWord[end];
end--;
i++;
}
reverseWord[length] = '\0';
return reverseWord;
}
Some useful tips:
There was an implicit declaration of function 'getch' which is invalid in C99
Unused variable 'p'
Use more descriptive names
I've created a variable with dynamic memory inside the function reverse. Otherwise address of stack memory associated with local variable 'reverseWord' is returned.
Best regards,
Denny
This question already has answers here:
Find the number of strings in an array of strings in C
(10 answers)
Closed 3 years ago.
I've been searching for hours how to find a way to pass strings to a function in C but they all seem to need either the length of the array or very specific information. I'm trying to make a function that will list a given array of strings so can vary in lengths in either dimension.
Currently I have:
void printStrings(char *arr[])
{
for (int i = 0; i < 2; i++)
{ //print all list items
printf(" %s\n", arr[i]);
}
}
int main(int argc, char *argv[])
{
char *list[2] = {"Hello", "Goodbye"};
printStrings(list);
return 0;
}
I want to be able to read the length of the array in printStrings to eliminate the hard coded 2 in the for loop so that it can run for all lengths.
This is not the same as asking the length of an array directly as it involves passing the array to a function.
you can use struct for this.
struct string_list{
char **list;
size_t len;
};
void printStrings(struct string_list s_list)
{
for (int i = 0; i < s_list.len; i++)
{ //print all list items
printf(" %s\n", s_list.list[i]);
}
}
int main(int argc, char *argv[])
{
struct string_list s_list;
char *list[2] = {"Hello", "Goodbye"};
s_list.list = list;
s_list.len = sizeof(list) / sizeof(list[0]);
printStrings(s_list);
}
If you want to stick to char* arrays, you don't. If you use C strings, they are 0 terminated and their length can be gotten with using strlen().
You can, however, do something like:
struct string {
char* String;
int Length;
};
And pass in an array of structs. Obviously you have to correctly assign the pointer to the correct strings and store the correct length of each.
Terminate the array of pointers with NULL. Then iterate until the NULL is found.
#include <stdio.h>
void printStrings(char *arr[])
{
int i = 0;
while ( arr[i])//not NULL
{ //print all list items
printf(" %s\n", arr[i]);
i++;
}
}
int main(int argc, char *argv[])
{
char *list[] = {"Hello", "Goodbye", NULL};
printStrings(list);
return 0;
}
This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 5 years ago.
This is core of the function i am currently writing.
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <cstring>
const char *words[] = {
"pigu",
// "third",
// "country",
// "human",
// "define",
};
#define word_count (sizeof(words) / sizeof(char *))
const char *allowed_chars = "abcdefghijklmnopqrstuvwxyz";
const char *get_random_word()
{
return words[rand() % word_count];
}
char *copy(const char *origin)
{
char *str = NULL;
str = (char *)malloc(sizeof(origin));
strcpy(str, origin);
return str;
}
int run()
{
const char *selected_word = get_random_word();
char *active_word = copy(selected_word);
char *placeholder_word = copy(selected_word);
char *left_chars = copy(allowed_chars);
free(active_word);
free(placeholder_word);
free(left_chars);
return 1;
}
int main(int argc, char *argv[])
{
srand(time(NULL));
while (run())
{
}
printf("\n");
return 0;
}
I have stripped out other code and managed to locate the problem to run function, which in this case will run infinitely, however while debugging I have set break points inside run function. Turns out that after running the function run for second time, the program crashes when it tries to execute free(placeholder_word);. Why is this happening and how could i prevent it.
Your copy function is wrong, sizeof(origin) returns the number of bytes needed
to store a pointer in memory, not the length of the string. So you've allocated
the incorrect number of bytes and if the length of the string is longer than
sizeof(origin) - 1, then you would overflow the buffer, which leads to
undefined behaviour which would explain the segfault.
It should be
char *copy(const char *origin)
{
char *str = NULL;
str = malloc(strlen(origin) + 1);
if(str == NULL)
return NULL;
strcpy(str, origin);
return str;
}
Note that I've removed the cast of malloc, which is not needed in C. If you
need it because this is a C++ program, the use new instead of malloc.
And you should always check if malloc returns NULL before accessing the
memory.
I have a string, for example: "Error_*_code_break_*_505_*_7.8"
I need to split the string with a loop by the delimiter "_*_" using the strstr function and input all parts into a new array, let's call it -
char *elements[4] = {"Error", "code_break", "505", "7.8"}
but strstr only gives me a pointer to a char, any help?
Note: the second string "code_break" should still contain "_", or in any other case.
This will get you half-way there. This program prints the split pieces of the string to the standard output; it does not make an array, but maybe you can add that yourself.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
void split(const char * str, const char * delimiter)
{
char * writable_str = strdup(str);
if (writable_str == NULL) { return; }
char * remaining = writable_str;
while (1)
{
char * ending = strstr(remaining, delimiter);
if (ending != NULL) { *ending = 0; }
printf("%s\n", remaining);
if (ending == NULL) { break; }
remaining = ending + strlen(delimiter);
}
free(writable_str);
}
int main(void) {
const char * str = "Error_*_code_break_*_505_*_7.8";
const char * delimiter = "_*_";
split(str, delimiter);
return 0;
}
Here is a function that splits a string into an array. You have to pass the size of the array so that the function won't overfill it. It returns the number of things it put into the array. What it puts into the array is a pointer into the string that was passed. It modifies the string by inserting null characters to end the pieces - just like strtok does.
#include<string.h>
#include<stdio.h>
int split(char *string, char *delimiter, char* array[], int size)
{
int count=0;
char *current=string;
char *next;
while(current && *current!='\0')
{
next=strstr(current,delimiter);
if(!next)break;
*next='\0';
if(count<size) array[count++]=current;
current=next+strlen(delimiter);
}
if(count<size) array[count++]=current;
return count;
}
int main()
{
char string[100]="Error_*_code_break_*_505_*_7.8";
char *array[10];
int size=split(string,"_*_",array,10);
for(int i=0;i<size;i++) puts(array[i]);
return size;
}