C segfault when modifiy array value [duplicate] - arrays

This question already has answers here:
Modify the content of char* str
(2 answers)
Closed 10 months ago.
Im getting a segfault when changing dna[i] to U, Ive debbuged but I still cant understand why.
Also I was comparing the value at a position against T with strcmp, but from what I understand thats for string literals and I can simply compare it with dna[i] == 'T'. Is that right? thanks.
#include <string.h>
char *dna_to_rna(char *dna) {
int size = (int)( sizeof(dna) / sizeof(dna[0]));
char *retour[size];
strcpy(retour, dna);
for (int i = 0; i < size; i++) {
if (dna[i] == 'T') {
dna[i] = 'U';
}
}
return (char *) retour;
}
int main() {
char *dna[] = {
"TTTT",
"GCAT",
"GACCGCCGCC"
};
char *actual, *expected;
size_t n;
for (n = 0; n < 3; ++n) {
actual = dna_to_rna(*(dna + n));
}
return 0;
}

You are passing to the function dna_to_rna a pointer to a string literal
actual = dna_to_rna(*(dna + n));
and then within the function you are trying to change the string literal
if (dna[i] == 'T') {
dna[i] = 'U';
}
Any attempt to change a string literal results in undefined behavior.
Also the expression with the sizeof operator in this declaration
int size = (int)( sizeof(dna) / sizeof(dna[0]));
does not make a sense. It evaluates the size of a pointer of the type char *.
Instead you should use the standard string function strlen.
And this declaration is incorrect
char *retour[size];
At least you need a character array instead of an array of pointers.
char retour[size];
And the function returns a pointer to an array with automatic storage duration that will not be alive after exiting the function
char *dna_to_rna(char *dna) {
//...
char retour[size];
//...
return (char *) retour;
}
that is the function returns an invalid pointer.
You should dynamically allocate a character array within the function with the length strlen( dna ) + 1 and change and return this array.
It seems what you mean is something like the following
#include <string.h>
#include <stdlib.h>
char * dna_to_rna( const char *dna )
{
size_t n = strlen( dna );
char *retour = malloc( n + 1 );
if ( retour != NULL )
{
strcpy( retour, dna );
for ( size_t i = 0; i < n; i++ )
{
if ( retour[i] == 'T' ) retour[i] = 'U';
}
}
return retour;
}

Related

Unexpected problem with Bidimensional char VLA pointer

I did a simple program that splits a string in substrings, using the whitespace as a split reference. The program was working as expected, so I've decided to put this code inside a function that is called "substring_whitespace".This function return a size_t value which is the number of substring's. The function arguments are char* buffer[] and char* string. Both are pointers, the first will store the substring's, and the second is the string that'll be splited.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
size_t substring_whitespace(char* buffer[],char* string) {
size_t initial_string_size = strlen(string) + 1;
char actual_string[initial_string_size];
char strings[initial_string_size][initial_string_size];
strcpy(actual_string,string);
size_t c = 0;
for(; c<initial_string_size; c++) {
size_t first_whitespace_index = strcspn(actual_string," ");
char substring[first_whitespace_index];
for(size_t d = 0; d<=first_whitespace_index; d++) {
if(d == first_whitespace_index)
substring[first_whitespace_index] = 0;
else
substring[d] = actual_string[d];
}
size_t actual_string_length = strlen(actual_string);
size_t new_actual_string_length = (actual_string_length - first_whitespace_index) + 1;
char new_actual_string[new_actual_string_length];
for(size_t d = 0,i = first_whitespace_index + 1; i<=actual_string_length + 1; i++,d++) {
if(i == actual_string_length)
new_actual_string[d] = 0;
else
new_actual_string[d] = actual_string[i];
}
strcpy(actual_string,new_actual_string);
strcpy(strings[c],substring);
buffer[c] = strings[c];
if(new_actual_string_length == 1)
break;
}
return ++c;\
}
int main() {
char string[1000];
fgets(string,sizeof(string)/sizeof(string[0]),stdin);
string[strcspn(string,"\n")] = 0;
char* buffer[strlen(string) + 1];
size_t buffer_length = substring_whitespace(buffer,string);
for(int d = 0; d<buffer_length; d++) {
printf("\n%s",buffer[d]);
}
}
After I test, the results were not as expected, so during my debug I detect that the char were being changed after get off the function by pointer. This behavior is only detectable if I try to print the buffer strings in the main.
strings is a local variable whose lifetime ends when the function returns. The easiest fix is to copy the string when assigning a value buffer[c]:
buffer[c] = strdup(strings[c]);
Another option is to change the design and return an array of ranges relative to your input string. For example struct range { char *s; size_t len; };, and if string is "hello world" the function could return [{string, 5}, {string+6, 5}].

Recursive Function return ordered vector

I have a problem with the return of that function, it should return the vector with the typed sequence, but it's returning an ordered sequence, could you tell me where I'm going wrong?
Create a recursive function that takes a string as input and also its length. This function should return how many times the character the substring “hi” appears in the string.
Prohibited
The first line in the input contains the number n of test cases. Next, n lines occur, each containing a string of maximum length equal to 5000 characters
Exit
The output consists of n lines, each containing an integer that indicates the number of times the string “hi” occurs in the input string. All strings are written in lowercase letters.
Example
Prohibited
4
hipotenuse hipothermia hilux hifi
hi
hihihi
xavante hey
Exit
4
1
3
0
My code:
#include <stdio.h>
#include <string.h>
#define MAX 5000
int ocorrencias(const char *palavra, size_t len) {
char *st = "hi";
return len ?
(*st == *palavra) + ocorrencias(palavra + 1, len - 1) :
0;
}
int main() {
int n,i;
scanf("%d",&n);
char palavra[MAX];
int re[n];
for(i=0; i<=n; i++){
fgets(palavra, MAX, stdin);
re[i] = ocorrencias(palavra, strlen(palavra));
}
for(i=0; i<=n; i++){
printf("%d\n", re[i]);
}
}
For starters the for loops like this
for(i=0; i<=n; i++){
^^^^^
are wrong.
You need to write
for(i=0; i < n; i++){
^^^^^^
The function ocorrencias should be declared either like
size_t ocorrencias( const char *palavra );
or like
size_t ocorrencias( const char *palavra, const char *st );
instead of
int ocorrencias(const char *palavra, size_t len) ;
because it deals with strings and the function is able to determine lengths of passed strings.
It can be defined for example the following way
size_t ocorrencias( const char *palavra )
{
const char *st = "hi";
const char *p = strstr( palavra, st );
return p == NULL ? 0 : 1 + ocorrencias( p + strlen( st ) );
}
So in main you should write
size_t re[n];
//...
for ( i = 0; i < n; i++ )
{
printf( "%zu\n", re[i] );
}
Otherwise if you want to count substrings either "hi" or "hy" (according to your comment to the question) then the function can look the following way
size_t ocorrencias( const char *palavra )
{
const char *p = strchr( palavra, 'h' );
return p == NULL ? 0 : ( p[1] == 'i' || p[1] == 'y' ) + ocorrencias( p + 1 );
}

Array of Strings some positions are not printing

So, I have an array of strings and the first two positions are not printing, I'm pretty sure it's a size problem, but I don't understand why
#include <stdio.h>
char * switch(int i) {
char letters[8][20] = {"Caio\0", "Eduarda\0", "Joanderson\0", "Heron\0", "Thiago\0", "Rafaela\0", "Thalisson\0", "Wilton\0"};
if ((i >=0) && (i<=7)) {
char*str = letters[i];
return (str);
} else {
return "-";
}
}
int main()
{
for(int i = 0; i < 8; i++){
printf("%d -- %s \n", i, switch(i));
}
return 0;
}
There are two ways to solve the problem:
Using dynamic memory allocation:
#include <stdio.h>
#include <stdlib.h>
char *switch1(int i)
{
char **letters = malloc(8 * sizeof(char *));
for (int i = 0; i < 8; i++)
{
letters[i] = malloc(20 * sizeof(char));
}
letters[0] = "Caio";
letters[1] = "Eduarda";
letters[2] = "Joanderson";
letters[3] = "Heron";
letters[4] = "Thiago";
letters[5] = "Rafaela";
letters[6] = "Thalisson";
letters[7] = "Wilton";
if ((i >= 0) && (i <= 7))
{
char *str = letters[i];
return (str);
}
else
{
return "-";
}
}
int main()
{
for (int i = 0; i < 8; i++)
{
printf("%d -- %s \n", i, switch1(i));
}
return 0;
}
Using static memory allocation :
#include <stdio.h>
char *switch1(int i)
{
static char letters[8][20] = {"Caio", "Eduarda", "Joanderson","Heron","Thiago", "Rafaela", "Thalisson", "Wilton"};
if ((i >= 0) && (i <= 7))
{
char *str = letters[i];
return (str);
}
else
{
return "-";
}
}
int main()
{
for (int i = 0; i < 8; i++)
{
printf("%d -- %s \n", i, switch1(i));
}
return 0;
}
I got an error, if I use switch as the name of the function. switch is keyword in C.
Lifetime of letters ends at the end of the switch1 function. We have to use static or dynamic memory allocation to extend its lifetime to entire program.
char letters[8][20] = …; defines an array with automatic storage duration. Memory is reserved for it only during the function call. The statement return (str); returns a pointer to an element of this array, and then the memory is no longer reserved for the array. In C’s abstract model of computing, the array ceases to exist. In typical practice, the array is on the stack, but the printf call overwrites it.
You can fix this by defining the array with static storage duration, which reserves memory for it during all of program execution:
static char letters[8][20] = {"Caio\0", "Eduarda\0", "Joanderson\0", "Heron\0", "Thiago\0", "Rafaela\0", "Thalisson\0", "Wilton\0"};
Additionally, it is not necessary to include a null character at the end of a quoted string. String literals automatically include a null character at the end.
Also, string literals define arrays with static storage duration themselves. So, instead of using the strings to initialize an array, you could instead point directly to the strings:
char *letters[8] = {"Caio", "Eduarda", "Joanderson", "Heron", "Thiago", "Rafaela", "Thalisson", "Wilton"};
That array could also be made static. It will work either way (because your function will not return a pointer to an element in the array but will return a pointer, taken from the array, that points to a string with static storage duration), but, if it is made static, it will not have to be initialized every time the function is called.

Allocate char array and strings

I have problem understanding the code below.
What value index=strlen(strs[0]) gets?
char *a= malloc (sizeof(char)*(index+1)) Is this the standard way to allocate array for char array?
What does strs[i][j] represent?
This is the code I found on leetcode. Just trying to understand the code. (code from sanghi user on leetcode)
#include<string.h>
char* longestCommonPrefix(char** strs, int strsSize)
{
int i=0; int j=0;int index;int tempindex=0;
if(strsSize<1)
return "";
index=strlen(strs[0]);
char *a;
a= malloc(sizeof(char)*(index+1));
strcpy(a,strs[0]);
for(i=1;i<strsSize;i++)
{ tempindex=0;
for(j=0;j<index;j++)
{
if(a[j]==strs[i][j])
tempindex++;
else
{a[j]='\0';
break;
}
}
if (tempindex==0)return ("");
if(tempindex<index)index=tempindex;
}
return a;
}
Expected results can be found on https://leetcode.com/problems/longest-common-prefix/
strs is an array of strings. strsSize is the number of strings in the array.
index = strlen(strs[0]);
This simply gets the length of strs[0], the first string in the array.
a = malloc(sizeof(char)*index+1);
This will allocate enough memory to store a string of the same size. I say enough memory because each string actually has length + 1 characters. The last character is \0, a null terminator. You always have to make sure to terminate your strings or else a bunch of weird buffer overflow stuff can happen.
str[i][j]
This accesses the jth character in the ith string in the array.
For starters the program is bad and invalid.:)
For example the size of the one dimensional array first element of which is pointed to by the parameter strs shall have the type size_t instead of int.
And all other variables that deal with indices also shall have the type size_t as for example
size_t index = strlen( strs[0] );
because the standard C function strlen has the return type size_t.
The source array is not changed in the function so the first parameter shall be declared with the qualifier const.
That is the function declaration shall look like
char * longestCommonPrefix( const char** strs, size_t strsSize);
Farther the elements (strings) of the array can have different lengths, So this loop
for(j=0;j<index;j++)
has undefined behavior because some element (string) of the array can have length less than the value of the variable index.
In fact there is no need to calculate lengths of the elements of the array. The loop can use the condition
for( j=0; j < index && strs[i][j] != '\0'; j++)
And moreover the function has a memory leak due to this return sub-statement in the if statement
a= malloc(sizeof(char)*(index+1));
//...
if (tempindex==0)return ("");
That is the allocated memory pointed to by the pointer a will not released.
What value index=strlen(strs[0]) gets?
index gets the length of the string stored in the first element of the array of strings.
For example if you have an array
char *strs[] = { "Hello", "Bye", "Good Morning" };
then index is set to the length of the string "Hello".
char a= malloc (sizeof(char)(index+1)) Is this the standard way to
allocate array for char array?
Yes in this declaration there is allocated a memory large enough to store the string (including its terminating zero) of the first element of the array pointed to by strs.
What does strs[i][j] represent?
strs[i][j] access j-th character of the i-th element of the array pointed to by strs.
For example for the declaration above strs[0][0] is equal to 'H', strs[0][1] is equal to 'e', strs[1][0] is equal to 'B' and so on.
P.S. A better approach to define the function is the following as it is shown in the demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t longestCommonPrefix( const char **strs, size_t strsSize )
{
size_t n = 0;
if ( strsSize != 0 )
{
n = strlen( *strs );
for ( size_t i = 1; n != 0 && i < strsSize; i++ )
{
size_t j = 0;
while ( j < n && strs[i][j] == strs[i-1][j] ) j++;
if ( j < n ) n = j;
}
}
return n;
}
int main(void)
{
char * strs[] = { "0123456789", "012345", "0123" };
size_t n = longestCommonPrefix( ( const char ** )strs, sizeof( strs ) / sizeof( *strs ) );
char *p = NULL;
if ( n != 0 )
{
p = malloc( n + 1 );
memcpy( p, strs[0], n );
p[n] = '\0';
printf( "The longest common prefix is \"%s\"\n", p );
}
free( p );
return 0;
}
The program output is
The longest common prefix is "0123"

Head First C string.h related questions

#include <stdio.h>
#include <string.h>
void print_reverse(char *s)
{
size_t len = strlen(s);
char *t = s + len - 1;
while (t >= s)
{
printf("%c", *t);
t = t - 1;
}
puts("");
}
Above is a function that will display a string backward on the screen. But I don't understand the 7th line (char *t = s+ len-1;). Could anybody explain this is spoken English please?
For starters this function
void print_reverse(char *s)
{
size_t len = strlen(s);
char *t = s + len - 1;
while (t >= s)
{
printf("%c", *t);
t = t - 1;
}
puts("");
}
is wrong and has undefined behavior.:)
There are two problems.
The first one is that the passed string as the argument can have a zero-length. In this case this declaration
char *t = s + len - 1;
will look like
char *t = s - 1;
and the pointer t can be wrong.
The second problem is that this expression statement
t = t - 1;
has undefined behavior in case when the pointer t is equal to s.
From the C Standard (6.5.6 Additive operators)
...If both the pointer operand and the result point to elements of the same
array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined.
A correct function implementation can look the following way
void print_reverse( const char *s)
^^^^^
{
size_t len = strlen(s);
const char *t = s + len;
^^^^^^^
while (t != s)
^^^^^^
{
printf("%c", *--t);
^^^^
}
puts("");
}
As for your question then in this declaration
char *t = s + len - 1;
the pointer t is tried to be initialized by the address of the last character of the string before the terminating zero.
Main logic behind this functions is that this code:
char *t = s+ len-1;
return a pointer to the address of the last char in the char pointer you are passing to the function. The loop prints it by decrementing it:
t = t - 1;
So in simple words it prints the char pointer from backwards.

Resources