I'm getting an error in the code and I don't know what it means, this is the first time I've come across it.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==30==ERROR: AddressSanitizer: SEGV on unknown address 0xffffffffffffffbe (pc 0x7f3dfc3c588c bp 0x7ffe82c73070 sp 0x7ffe82c727d0 T0)
==30==The signal is caused by a READ memory access.
#0 0x7f3dfc3c588b (/lib/x86_64-linux-gnu/libasan.so.5+0xd688b)
#3 0x7f3dfb7b70b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libasan.so.5+0xd688b)
==30==ABORTING
I need to reverse every words in a line.I think it occurs in the second cycle. my idea is to find the first and last index of each words. This is my code:
char * reverseWords(char * s){
int n = strlen(s);
char *res = malloc(sizeof(char) * n);
int firstI, lastI;
for (int i = 0; i < n; i++){
firstI = i;
while (++i < n && strcmp(res[i], ' ') == 0){
lastI = i - 1;
}
while (firstI > lastI){
char temp = res[firstI];
res[firstI++] = res[lastI];
res[lastI--] = temp;
}
}
return res;
}
new code
char * reverseWords(char * s){
int n = strlen(s);
char *res = malloc(n + 1);
strcpy(res, s);
int firstI, lastI;
for (int i = 0; i < n; i++){
firstI = i;
while (++i < n && res[i] == ' '){
lastI = i - 1;
}
while (firstI > lastI){
char temp = res[firstI];
res[firstI++] = res[lastI];
res[lastI--] = temp;
}
}
return res;
}
Off by one error:
int n = strlen(s);
char *res = malloc(sizeof(char) * n);
strlen() does not count the terminating null-byte. You did not allocate space for it.
Lack of null-terminator:
return res;
You do not null-terminate res before returning.
strcmp() compares strings:
strcmp(res[i], ' ')
The arguments to strcmp() must be char *s, not chars.
Aside: Code risks undefined behavior if malloc() returned NULL.
Edit: Current code is too complicated. I simplified things and added some checks.
static char *reverseWords(char *str)
{
/* NULL pointer. */
if (!str) {
return 0;
}
/* Empty string. */
if (*str == '\0') {
return 0;
}
/* Assuming it's null-terminated. */
char *src = str;
char *dest = src + (strlen(str) - 1); /* -1 for the null-byte. */
/* ++ and -- have higher precedence than the * operator.
* But, in an expression, they return the old value of their
* operand. So this copies first, then increments the pointer
* point to the next char.
*/
while (src < dest) {
char tmp = *src;
*src++ = *dest;
*dest-- = tmp;
}
return str;
}
Sample I/O:
Input: Hello
Output: olleH
Related
I'm trying to solve a challenge, but I have no idea of what's wrong with my code!
The challenge is:
Create a function that splits a string of characters into words.
Separators are spaces, tabs and line breaks.
This function returns an array where each box contains a character-string’s address represented by a word. The last element of this array should be equal to 0 to emphasise the end of the array.
There can’t be any empty strings in your array. Draw the necessary conclusions.
The given string can’t be modified.
Note: The only allowed function is malloc()
The bug/problem:
I faced this problem and I tried to solve it but I wasn't able to identify what's wrong.
I created a function named split_whitespaces() to do the job.
When I print the array of strings inside of the split_whitespaces function, I get the following output:
Inside the function:
arr_str[0] = This
arr_str[1] = is
arr_str[2] = just
arr_str[3] = a
arr_str[4] = test!
And when I print the array of string inside the main function, I get the following output:
Inside the main function:
arr_str[0] = #X#?~
arr_str[1] = `X#?~
arr_str[2] = just
arr_str[3] = a
arr_str[4] = test!
I created a function word_count to count how many words in the input string so I can allocate memory using malloc and with word_count + 1 (null pointer).
int word_count(char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
i++;
} else {
state = 0;
i++;
}
}
return (w_count);
}
And another function called strdup_w to mimic the behavior of strdup but just for single words:
char *strdup_w(char *str, int *index) {
char *word;
int len;
int i;
i = *index;
len = 0;
while (str[i] && !iswhitespace(str[i]))
len++, i++;;
word = (char *) malloc(len + 1);
if (!word)
return (NULL);
i = 0;
while (str[*index]) {
if (!iswhitespace(str[*index])) {
word[i++] = str[*index];
(*index)++;
} else
break;
}
word[len] = '\0';
return (word);
}
Here's my full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **split_whitespaces(char *str);
char *strdup_w(char *str, int *index);
int word_count(char *str);
int iswhitespace(char c);
int main(void) {
char *str = "This is just a test!";
char **arr_str;
int i;
i = 0;
arr_str = split_whitespaces(str);
printf("\nOutside the function:\n");
while (arr_str[i]) {
printf("arr_str[%d] = %s\n", i, arr_str[i]);
i++;
}
return (0);
}
char **split_whitespaces(char *str) {
char **arr_str;
int i;
int words;
int w_i;
i = 0;
w_i = 0;
words = word_count(str);
arr_str = (char **)malloc(words + 1);
if (!arr_str)
return (NULL);
printf("Inside the function:\n");
while (w_i < words) {
while (iswhitespace(str[i]) && str[i])
if (!str[i++])
break;
arr_str[w_i] = strdup_w(str, &i);
printf("arr_str[%d] = %s\n", w_i, arr_str[w_i]);
w_i++;
}
arr_str[words] = 0;
return (arr_str);
}
char *strdup_w(char *str, int *index) {
char *word;
int len;
int i;
i = *index;
len = 0;
while (str[i] && !iswhitespace(str[i]))
len++, i++;;
word = (char *)malloc(len + 1);
if (!word)
return (NULL);
i = 0;
while (str[*index]) {
if (!iswhitespace(str[*index])) {
word[i++] = str[*index];
(*index)++;
} else
break;
}
word[len] = '\0';
return (word);
}
int word_count(char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
i++;
} else {
state = 0;
i++;
}
}
return (w_count);
}
int iswhitespace(char c) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
return (1);
return (0);
}
I'm sorry, if anything this is my first time trying to seek help.
There are multiple problems in the code:
the size is incorrect in arr_str = (char **)malloc(words + 1); You must multiply the number of elements by the size of the element:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
it is good style to free the array in the main() function after use.
the test while (iswhitespace(str[i]) && str[i]) is redundant: if w_count is computed correctly, testing str[i] should not be necessary. You should use strspn() to skip the white space and strcspn() to skip the word characters.
if (!str[i++]) break; is completely redundant inside the loop: str[i] has already been tested and is not null.
while (str[i] && !iswhitespace(str[i])) len++, i++;; is bad style. Use braces if there is more than a single simple statement in the loop body.
the last loop in strdup_w is complicated, you could simply use memcpy(word, str + *index, len); *index += len;
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
char **split_whitespaces(const char *str);
char *strdup_w(const char *str, int *index);
int word_count(const char *str);
int iswhitespace(char c);
int main(void) {
const char *str = "This is just a test!";
char **arr_str;
int i;
arr_str = split_whitespaces(str);
if (arr_str) {
printf("\nOutside the function:\n");
i = 0;
while (arr_str[i]) {
printf("arr_str[%d] = %s\n", i, arr_str[i]);
i++;
}
while (i --> 0) {
free(arr_str[i]);
}
free(arr_str);
}
return 0;
}
char **split_whitespaces(const char *str) {
char **arr_str;
int i;
int words;
int w_i;
i = 0;
w_i = 0;
words = word_count(str);
arr_str = malloc(sizeof(*arr_str) * (words + 1));
if (!arr_str)
return NULL;
printf("Inside the function:\n");
while (w_i < words) {
while (iswhitespace(str[i]))
i++;
arr_str[w_i] = strdup_w(str, &i);
if (!arr_str[w_i])
break;
printf("arr_str[%d] = %s\n", w_i, arr_str[w_i]);
w_i++;
}
arr_str[words] = NULL;
return arr_str;
}
char *strdup_w(const char *str, int *index) {
char *word;
int len;
int start;
int i;
i = *index;
start = i;
while (str[i] && !iswhitespace(str[i])) {
i++;
}
*index = i;
len = i - start;
word = malloc(len + 1);
if (!word)
return NULL;
i = 0;
while (i < len) {
word[i] = str[start + i];
i++;
}
word[i] = '\0';
return word;
}
int word_count(const char *str) {
int i;
int w_count;
int state;
i = 0;
w_count = 0;
state = 0;
while (str[i]) {
if (!iswhitespace(str[i])) {
if (!state)
w_count++;
state = 1;
} else {
state = 0;
}
i++;
}
return w_count;
}
int iswhitespace(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
From my top comment ...
In split_whitespaces, try changing:
arr_str = (char **) malloc(words + 1);
into:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
As you have it, words is a count and not a byte length, so you're not allocating enough space, so you have UB.
UPDATE:
But watched some tutorials and they said that malloc takes one argument which is the size of the memory to be allocated (in bytes), that's why I allocated memory for 5 bytes! can you please tell my an alternative of using malloc without sizeof() function. I'll appreciate it. – Achraf EL Khnissi
There's really no clean way to specify this without sizeof.
sizeof is not a function [despite the syntax]. It is a compiler directive. It "returns" the number of bytes occupied by its argument as a compile time constant.
If we have char buf[5];, there are 5 bytes, so sizeof(buf) [or sizeof buf] is 5.
If we have: int buf[5];, there are 5 elements, each of size int which is [typically] 4 bytes, so the total space, in bytes, is sizeof(int) * 5 or 4 * 5 which is 20.
But, int can vary depending on the architecture. On Intel 8086's [circa the 1980's], an int was 2 bytes (i.e. 16 bits). So, the above 4 * 5 would be wrong. It should be 2 * 5.
If we use sizeof(int), then sizeof(int) * 5 works regardless of the architecture.
Similarly, on 32 bit machines, a pointer is [usually] 32 bits. So, sizeof(char *) is 4 [bytes]. On a 64 bit machine, a pointer is 64 bits, which is 8 bytes. So, sizeof(char *) is 8.
Because arr_str is: char **arr_str, we could have done:
arr_str = malloc(sizeof(char *) * (words + 1));
But, if the definition of arr_str ever changed (to (e.g.) struct string *arr_str;), then what we just did would break/fail if we forgot to change the assignment to:
arr_str = malloc(sizeof(struct string) * (words + 1));
So, doing:
arr_str = malloc(sizeof(*arr_str) * (words + 1));
is a preferred idiomatic way to write cleaner code. More statements will adjust automatically without having to find all affected lines of code manually.
UPDATE #2:
You might just add why you removed the (char **) cast :) -- chqrlie
Note that I removed the (char **) cast. See: Do I cast the result of malloc?
This just adds extra/unnecessary "stuff" as the void * return value of malloc can be assigned to any type of pointer.
If we forgot to do: #include <stdlib.h>, there would be no function prototype for malloc, so the compiler would default the return type to int.
Without the cast, the compiler would issue an an error on the statement [which is what we want].
With the cast, this action is masked at compile time [more or less]. On a 64 bit machine, the compiler will use a value that is truncated to 32 bits [because it thinks malloc returns a 32 bit value] instead of the full 64 bit return value of malloc.
This truncation is a "silent killer". What should have been flagged as a compile time error produces a runtime fault (probably segfault or other UB) that is much harder to debug.
I usually try hard and harder to solve myself any bugs I find in my code, but this one is totally out of any logic for me. It works really fine with whatever strings and char separators, but only with that useless printf inside the while of the function, otherwise it prints
-> Lorem
then
-> ▼
and crashes aftwerwards. Thanks in advance to anyone that could tell me what is happening.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
char **strsep_(char *str, char ch) {
// Sub-string length
uint8_t len = 0;
// The number of sub-strings found means the same as the position where it will be stored in the main pointer
// Obviously, the number tends to increase over time, and at the end of the algorithm, it means the main pointer length too
uint8_t pos = 0;
// Storage for any found sub-strings and one more byte as the pointer is null-terminated
char **arr = (char**)malloc(sizeof(char **) + 1);
while (*str) {
printf("Erase me and it will not work! :)\n");
if (*str == ch) {
// The allocated memory should be one step ahead of the current usage
arr = realloc(arr, sizeof(char **) * pos + 1);
// Allocates enough memory in the current main pointer position and the '\0' byte
arr[pos] = malloc(sizeof(char *) * len + 1);
// Copies the sub-string size (based in the length number) into the previously allocated space
memcpy(arr[pos], (str - len), len);
// `-_("")_-k
arr[pos][len] = '\0';
len = 0;
pos++;
} else {
len++;
}
*str++;
}
// Is not needed to reallocate additional memory if no separator character was found
if (pos > 0) arr = realloc(arr, sizeof(char **) * pos + 1);
// The last chunk of characters after the last separator character is properly allocated
arr[pos] = malloc(sizeof(char *) * len + 1);
memcpy(arr[pos], (str - len), len);
// To prevent undefined behavior while iterating over the pointer
arr[++pos] = NULL;
return arr;
}
void strsep_free_(char **arr) {
char **aux = arr;
while (*arr) {
free(*arr);
*arr = NULL;
arr++;
}
// One more time to fully deallocate the null-terminated pointer
free(*arr);
*arr = NULL;
arr++;
// Clearing The pointer itself
free(aux);
aux = NULL;
}
int main(void) {
char **s = strsep_("Lorem ipsum four words", ' ');
char **i = s;
while (*i != NULL) {
printf("-> %s\n", *i);
i++;
}
strsep_free_(s);
}
Your program has undefined behavior, which means it may behave in unexpected ways, but could by chance behave as expected. Adding the extra printf changes the behavior in a way the seems to correct the bug, but only by coincidence. On a different machine, or even on the same machine at a different time, the behavior may again change.
There are multiple bugs in your program that lead to undefined behavior:
You are not allocating the array with the proper size: it should have space fpr pos + 1 pointers, hence sizeof(char **) * (pos + 1). The faulty statements are: char **arr = (char**)malloc(sizeof(char **) + 1); and arr = realloc(arr, sizeof(char **) * pos + 1);.
Furthermore, the space allocated for each substring is incorrect too: arr[pos] = malloc(sizeof(char *) * len + 1); should read arr[pos] = malloc(sizeof(char) * len + 1);, which by definition is arr[pos] = malloc(len + 1);. This does not lead to undefined behavior, you just allocate too much memory. If your system supports it, allocation and copy can be combined in one call to strndup(str - len, len).
You never check for memory allocation failure, causing undefined behavior in case of memory allocation failure.
Using uint8_t for len and pos is risky: what if the number of substrings exceeds 255? pos and len would silently wrap back to 0, producing unexpected results and memory leaks. There is no advantage at using such a small type, use int or size_t instead.
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **strsep_(const char *str, char ch) {
// Sub-string length
int len = 0;
// The number of sub-strings found, index where to store the NULL at the end of the array.
int pos = 0;
// return value: array of pointers to substrings with an extra slot for a NULL terminator.
char **arr = (char**)malloc(sizeof(*arr) * (pos + 1));
if (arr == NULL)
return NULL;
for (;;) {
if (*str == ch || *str == '\0') {
// alocate the substring and reallocate the array
char *p = malloc(len + 1);
char **new_arr = realloc(arr, sizeof(*arr) * (pos + 2));
if (new_arr == NULL || p == NULL) {
// allocation failure: free the memory allocated so far
free(p);
if (new_arr)
arr = new_arr;
while (pos-- > 0)
free(arr[pos]);
free(arr);
return NULL;
}
arr = new_arr;
memcpy(p, str - len, len);
p[len] = '\0';
arr[pos] = p;
pos++;
len = 0;
if (*str == '\0')
break;
} else {
len++;
}
str++;
}
arr[pos] = NULL;
return arr;
}
void strsep_free_(char **arr) {
int i;
// Free the array elements
for (i = 0; arr[i] != NULL; i++) {
free(arr[i]);
arr[i] = NULL; // extra safety, not really needed
}
// Free The array itself
free(arr);
}
int main(void) {
char **s = strsep_("Lorem ipsum four words", ' ');
int i;
for (i = 0; s[i] != NULL; i++) {
printf("-> %s\n", s[i]);
}
strsep_free_(s);
return 0;
}
Output:
-> Lorem
-> ipsum
-> four
-> words
The probable reason for the crash is most likely this: realloc(arr, sizeof(char **) * pos + 1).
That is the same as realloc(arr, (sizeof(char **) * pos) + 1) which does not allocate enough space for your "array". You need to do realloc(arr, sizeof(char **) * (pos + 1)).
Same with the allocation for arr[pos], you need to use parentheses correctly there too.
Good answer from #chqrlie. From my side, I think it would be better to count everything before copy, it should help to avoid realloc.
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int count_chars(const char *str, const char ch)
{
int i;
int count;
i = 0;
count = 0;
if (*str == ch)
str++;
while (str[i] != ch && str[i] != '\0')
{
count++;
i++;
}
return (count);
}
int count_delimeter(const char *str, const char ch)
{
int i = 0;
int count = 0;
while (str[i])
{
if (str[i] == ch && str[i + 1] != ch)
count++;
i++;
}
return count;
}
char** strsep_(const char *str, const char ch)
{
char **arr;
int index = 0;
int size = 0;
int i = 0;
size = count_delimeter(str, ch) + 1;
if ((arr = malloc(sizeof(char *) * (size + 1))) == NULL)
return (NULL);
arr[size] = NULL;
while (i < size)
{
if (str[index] == ch)
index++;
if (str[index] && str[index] == ch && str[index + 1] == ch)
{
while (str[index] && str[index] == ch && str[index + 1] == ch)
index++;
index++;
}
int len = count_chars(&str[index], ch);
if ((arr[i] = malloc(sizeof(char) * (len + 1))) == NULL)
return NULL;
memcpy(arr[i], &str[index], len);
index += len;
arr[i++][len] = '\0';
}
return arr;
}
int main(void)
{
char *str = "Lorem ipsum ipsum Lorem lipsum gorem insum";
char **s = strsep_(str, ' ');
/* char *str = "Lorem + Ipsum"; */
/* char **s = strsep_(str, '+'); */
/* char *str = "lorem, torem, horem, lorem"; */
/* char **s = strsep_(str, ','); */
while (*s != NULL) {
printf("-> [%s]\n", *s);
s++;
}
/* dont forget to free */
return 0;
}
I'm writing a CLI input parser and I want to know what is the fastest algorithm to split a string into tokens.
Rules:
A space means end of the token.
Any char can be escaped with a backslash which means that I take it as is without any specal meaning. (currently only used for escaping a space)
Here is the code I am currently using:
#define POINTER_ARRAY_STEP 10
#define STRING_STEP 255
char **parse_line(char *line)
{
char **array;
size_t array_len;
size_t array_index;
size_t token_len;
size_t token_index;
array_len = POINTER_ARRAY_STEP;
array = malloc((array_len + 1) * sizeof(char*)); /* +1 to leave space for NULL */
array_index = 0;
token_len = STRING_STEP;
array[array_index] = malloc(token_len + 1);
token_index = 0;
for (; *line; ++line) {
if (array_index == array_len) {
array_len += POINTER_ARRAY_STEP;
array = realloc(array, (array_len + 1) * sizeof(char*));
}
if (token_index == token_len) {
token_len += STRING_STEP;
array[array_index] = realloc(array[array_index], token_len + 1);
}
if (*line == '\\') {
array[array_index][token_index++] = *++line;
continue;
}
if (*line == ' ') {
array[array_index][token_index] = 0;
array[++array_index] = malloc(token_len + 1);
token_index = 0;
continue;
}
array[array_index][token_index++] = *line;
}
/* Null terminate the last array element */
array[array_index][token_index] = 0;
/* Null terminate the array */
array[array_index + 1] = NULL;
return array;
}
Your method is both unsafe and inefficient: you do not check for memory allocation failure and you call realloc() way too many times.
Here is another approach:
make a first pass to count the number of tokens and escapes,
allocate the pointer array and a buffer for the tokens
make a second pass, copying the characters into the buffer, splitting the tokens and making the pointer array point to the tokens.
return the array pointer.
The memory can later be freed by calling free() on both the pointer array and its first element.
Here is the code:
#include <stdlib.h>
char **parse_line(const char *line) {
size_t len, i, j, k, items = 1, escapes = 0;
char **array;
char *buf;
for (len = 0; line[len]; len++) {
if (line[len] == '\\') {
escapes++;
if (line[++len] == '\0')
break;
} else
if (line[len] == ' ') {
items++;
}
}
if (len == escapes) {
/* special case empty line */
array = malloc(sizeof(*array));
if (array != NULL) {
array[0] = NULL;
}
return array;
}
array = malloc((items + 1) * sizeof(*array));
buf = malloc(len + 1 - escapes);
if (array == NULL || buf == NULL) {
free(array);
free(buf);
return NULL;
}
items[0] = buf;
k = 1;
for (i = j = 0; i < len; i++) {
if (line[i] == '\\') {
if (++i == len)
break;
buf[j++] = line[i];
} else
if (line[i] == ' ') {
buf[j++] = '\0';
items[k++] = buf + j;
} else {
buf[j++] = line[i];
}
}
buf[j] = '\0';
items[k] = NULL;
return items;
}
Suggested fastest algorithm
Make only 2 passes. Once to find token count and length of buffer needed.
2nd time to chop up duplicated line.
The array of tokens point to a single allocated memory, so when done, tokens[0] needs to be free'd as well as tokens.
As OP asked for a faster algorithm, below is $pseudo code$/code.
char **parse_line(const char *line) {
size_t token_count = 1;
const char *p = line;
$Let `p` each element in `line`$
$if `*p` is a separator, increment `token_count`
$else `*p` is an escape not followed by a \0$
$advance `p`$
}
}
$ `p`, at the end of the string, so allocate enough for a $
$ duplicate +1 based on the difference of `p` and the start. $
$ Check allocation success $
$ Copy into `char *line_buffer` $
// The token count is known, get enough pointers + 1 and check
char **tokens = malloc(sizeof *tokens * (token_count + 1));
// More complex code could perform only 1 allocation for `tokens` and `line_buffer`
$ Let `q` be first element in line_buffer
$ Let `d` be the same (destination pointer)
$ set begin_token flag $
size_t token_index = 0;
for (;;) {
$ if begin_token flag set $ {
$ clear begin_token $
tokens[token_index] = q;
d = q;
}
$ if `*q` separator (space or \0) $ {
*d = '\0';
token_index++;
$ if *q at end of string $ break;
$ set begin_token flag $
$else {
if `*q` is an escape not followed by a \0$
$advance q$
}
$copy *q to *d, advance both pointers.
}
}
$set last tokens[] to NULL$
return tokens;
}
I wrote the following function to inverse a string s
char *strinverse( const char *s ){
char *t;
int i = 0;
while (*s) {
s++;
i++;
}
while (i >= 0){
s--;
*t = *s;
t++;
i--;
}
*t = '\0';
return t;
}
int main(void){
char v[4]="abc";
char r[4];
char *pr = r;
pr = strinverse(v);
printf("%s", pr);
return 0;
}
The idea is to find out the length of the string s in the first while-loop, then to decrease the pointer of s while copying the respective values into t. For some reason the program crashes and the compiler gives me no information. Maybe there's something wrong in the main function? Thanks for your advices!
Answer edited
#include<stdio.h>
#include<stdlib.h>
char *strinverse(const char *s ){
char *t, *p;
int i = 0;
while (*s) {
s++;
i++;
}
t = (char*)malloc((i + 1) * sizeof(char)); //added this!
p = t;
while (i >= 0){
s--;
*t = *s;
t++;
i--;
}
*t = '\0';
return p;
}
int main(void){
char v[4]="abc";
char *pr;
pr = strinverse(v);
printf("%s\n", pr);
return 0;
}
The reason that program crashes is that you have not allocated space for pointer t. In this case your program invokes undefined behavior. Allocate space for t
t = malloc(i + 1);
Do not forget to free memory at the end using free(t).
I would use a function that changes the string in-place instead.
void reversestr(char *s)
{
char tmp;
size_t i, len = strlen(s);
for (i = 0; i < len / 2; i++) {
tmp = s[i];
s[i] = s[len - 1 - i];
s[len - 1 - i] = tmp;
}
s[len] = '\0';
}
If you need the reversed string separately, you can just use strdup before you call reversestr. BTW: function names that start with "str" are reserved for functions of the C standard library.
you have not make malloc in the pointer "t" and you have problem in this line "*t = *s;"
I'm writing code for an assignment where we have to create a hashtable. One of the functions is to get all the keys within the hash table and assign it into a char* ** (triple pointer) given by the parameters. The char* ** is presumed to be empty, and so we have to allocate memory to it within the function to fit all the keys.
The problem I'm having is where, after I allocate memory (and presumably the right amount, with strlen + 1), the program crashes and valgrind gives me an error message of invalid read of size 8, as well as a bunch of unconditional jumps and finally Process terminating with default action of signal 11 (SIGSEGV) Access not within mapped region at address 0x0.
int GetKeys( HashTablePTR hashTablePtr, char ***keysArrayHandle, unsigned int *keyCount )
{
HashTablePTR head;
int counter = 0;
size_t length = 0;
*keyCount = 0;
head = hashTablePtr;
if (NULL == hashTablePtr || 0xDEADBEEF != hashTablePtr[0].sentinel)
{
return(-1);
}
else
{
// Get key count
for (int i = 0; i < (int) head[0].range; i++)
{
hashTablePtr = &(head[i]);
while (NULL != hashTablePtr && NULL != hashTablePtr->key)
{
*keyCount = *keyCount + 1;
hashTablePtr = hashTablePtr->next;
}
}
printf("keyCount: [%d]\n", *keyCount);
}
keysArrayHandle = malloc(sizeof(char **) * (*keyCount));
for(int j = 0; j < (int) head[0].range; j++)
{
hashTablePtr = &(head[j]);
while (NULL != hashTablePtr && NULL != hashTablePtr->key && counter < *keyCount)
{
length = strlen(hashTablePtr->key) + 1;
keysArrayHandle[counter] = malloc(sizeof(char) * length);
printf("%s\n", hashTablePtr->key);
///////SOMETHING IS WRONG WITH THIS LINE UNDERNEATH////////
memcpy(*(keysArrayHandle[counter]), hashTablePtr->key, length);
printf("String copied\n");
counter++;
hashTablePtr = hashTablePtr->next;
}
}
return(0);
}
keysArrayHandle[counter] = malloc(sizeof(char) * length);
returns a pointer to keysArrayHandle[counter].
Then you are using *(keysArrayHandle[counter]) instead of keysArrayHandle[counter] in memcpy.
maybe you should
*(keysArrayHandle[counter]) = malloc(sizeof(char) * length);
valter
I think you should not dereference that pointer there
something = malloc(size);
memcpy(something, x, size); /* instead of memcpy(*something ... */
Also, check mpthe value returned by malloc