I've been doing this code wars challenge in which you have to take a string, and capitalize each letter, forming a Mexican wave-looking array of strings. For example, an input string like
hello
will result in ["Hello", "hEllo", "heLlo", "helLo", "hellO"]
I managed to complete it in JavaScript, and decided to attempt it in C. The actual code itself is working, as it prints the correct output, but the problem I am having is actually storing the string inside a double pointer.
This is my code:
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void wave(char *s, char **array);
int main(void)
{
char *s = malloc(6);
strcpy(s, "hello");
char **array = malloc(pow(strlen(s)+1, 2));
wave(s, array);
for (int i = 0; i < strlen(s); i++)
{
printf("s = %s\n", array[i]);
}
free(array);
free(s);
return 0;
}
void wave(char *s, char **array)
{
char s2[strlen(s)+1];
for (int i = 0; i < strlen(s); i++)
{
s[i] = tolower(s[i]);
}
int array_index = 0;
for (int i = 0; i < strlen(s); i++)
{
strcpy(s2, s);
if (s[i] != ' ')
{
s2[i] = toupper(s2[i]); // Printing out `s2` here results in the correct output
array[array_index++] = s2; // Adding it here works, but when trying to access it outside of this function, it gives the incorrect output
}
}
}
When printing the string inside the function, I get the following output (which is correct):
Hello
hEllo
heLlo
helLo
hellO
But when I try to print it out inside the main() function, I get the following:
s = hellO
s = hellO
s = hellO
s = hellO
s = hellO
It seems like it is adding/accessing only the last string in the array. I cannot understand why accessing the element inside the wave() function works, but accessing it outside of that function doesn't.
I've had this problem twice before, both in C and C++, and have been unable to solve it, and it is really annoying me.
I left this as a comment, but since it might not be clear, I'll post my answer in code...
As stated in my comment, there's no point allocating a pointer array - on a 64 bit machine, that would be 6 pointers, each requiring 8 bytes to point at a 7 byte long data block - a total of 104 bytes (ignoring the added allocator padding per allocation).
Instead, a single allocation could suffice, allocating 42 bytes to contain all the "wave" strings and their NUL byte in a single block of memory (saving memory while improving locality).
int main(void) {
/* Assuming string "hello" */
const char *org = "hello";
/* Calculate length only once and store value */
const size_t len = strlen(org);
const size_t len_with_nul = len + 1;
/* Allocate `len` strings in a single allocation */
char *buf = malloc(len * len_with_nul);
/* Copy each string to it's place in the buffer */
for (size_t i = 0; i < len; ++i) {
/* position in the buffer */
char *pos = buf + (i * len_with_nul);
/* copy the NUL as well */
memcpy(pos, org, len_with_nul);
/* Wave... */
pos[i] = toupper(pos[i]);
}
/* Print result */
for (size_t i = 0; i < len; i++) {
char *pos = buf + (i * len_with_nul);
printf("s = %s\n", pos);
}
/* Free buffer */
free(buf);
return 0;
}
EDIT - Why is using a single memory block better?:
In this case we allocate a single memory "block" (blob / slice). This offers a number of advantages:
We perform a single allocation and deallocation instead of a larger number of allocations and deallocations.
This improves speed by performing less actions.
We also improve memory locality, which minimizes CPU cache misses and improves performance.
We use less memory.
Each memory allocation comes with a price - we need a pointer to hold the memory address for the memory we allocated. A pointer "costs" 8 bytes on a 64bit machine and 4 bytes on a 32bit machine.
By using a single allocation, we "pay" less.
This is true even if we ignore the metadata attached to the memory block allocated (which requires memory from the memory allocator).
I should note that C doesn't really care about the contents of a memory block, it's all zeros and ones. The meaning given to these zeros and ones is left to the developer.
Even the printf function doesn't care about the contents of the memory it's reading - it simply reads the memory according to the formatting it was instructed to follow by the developer (the %s informs the function that the memory relates to a NUL terminated string).
There are some concerns about memory alignment which are CPU and system specific - but these don't apply to single byte strings. They apply to multi-byte types (such as short, int, and long). So we don't need to worry about them in this example.
In this sense, it basically means that the developer is free to manage the memory and the contents as they see fit (putting aside memory alignment).
This is not to say that it's always better to allocate a single block of memory (if you need to use realloc, you might prefer smaller chunks)... but usually a single block of memory is better.
For starters it is unclear why you are allocating dynamically memory for the string literal "hello".
char *s = malloc(6);
strcpy(s, "hello");
It does not make any sense.
Just write
const char *s = "hello";
This declaration
char **array = malloc(pow(strlen(s), 2));
also does not make sense. What you need is the following.
size_t n = strlen( s );
char **array = malloc( n * sizeof( char * ) );
for ( size_t i = 0; i < n; i++ )
{
array[i] = malloc( n + 1 );
}
The function wave can be defined the following way
void wave( const char *s, char **array )
{
size_t n = strlen( s );
for ( size_t i = 0; i < n; i++ )
{
strcpy( array[i], s );
array[i][i] = toupper( ( unsigned char )s[i] );
}
}
and then in main after the function call
for ( size_t i = 0; i < n; i++ )
{
puts( array[i] );
}
for ( size_t i = 0; i < n; i++ ) free( array[i] );
free( array );
Here is the full program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void wave( const char *s, char **array )
{
size_t n = strlen( s );
for ( size_t i = 0; i < n; i++ )
{
strcpy( array[i], s );
array[i][i] = toupper( ( unsigned char )s[i] );
}
}
int main(void)
{
const char *s = "hello";
size_t n = strlen( s );
char **array = malloc( n * sizeof( char * ) );
for ( size_t i = 0; i < n; i++ )
{
array[i] = malloc( n + 1 );
}
wave( s, array );
for ( size_t i = 0; i < n; i++ )
{
puts( array[i] );
}
for ( size_t i = 0; i < n; i++ ) free( array[i] );
free( array );
return 0;
}
Its output is
Hello
hEllo
heLlo
helLo
hellO
Related
I am trying to write a simple piece of code that merges two strings together in even and odd indexes.
This is the code
void two_strings(char a[], char b[]) {
int counta = 0, countb = 0;
int lena = strlen(a);
int lenb = strlen(b);
int lenab = lena + lenb;
char ans[lenab];
for(int i = 0; i<strlen(ans); i++) {
if(i%2 == 0) {
ans[i] = a[counta];
counta++;
}
else {
ans[i] = b[countb];
countb++;
}
}
printf("%s\n", ans);
}
This is the main:
int main() {
char a[] = "hello";
char b[] = "bye";
two_strings(a, b);
return 0;
}
I have compiled it with -Wall and didn't get any warnings or errors, and I have tried it also with long instead of int just to check if that was the issue. when I run the code it doesn't get past the first strlen(a)
Strings in C are defined as a sequence of non-null bytes followed by a terminating null byte ('\0').
The following are equivalent strings
char one[] = "hello";
char two[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
Both of these would have a string length of 5, and occupy 6 bytes of memory.
String handling functions in the Standard Library expect this null-terminating byte, and you will invoke Undefined Behavior by passing a non-null-terminated array to them. strlen and printf (with %s) are examples of these kinds of functions.
In your two_strings function you are not allocating enough memory to store the null-terminating byte. You also make no attempt to place this null-terminating byte in the array.
Allocate an additional byte for the null-terminating byte, and do not attempt to take the string length of an uninitialized array.
void two_strings(char a[], char b[]) {
/* ... */
size_t length = strlen(a) + strlen(b);
char string[length + 1];
for (size_t i = 0; i < length; i++) {
/* ... */
}
string[length] = '\0';
/* ... */
}
Also note that size_t is the correct type to use when dealing with memory indexing, and is the type returned by strlen.
As for your algorithm, in the event where your input strings differ in length you will attempt to continue indexing one of the strings after you have already reached its end.
You will either want to: only take the smaller string's length of characters from the larger string, stopping when the smaller string has been exhausted; or, append the remaining characters of the larger string to the result after the smaller string has been exhausted.
A quick example of the second approach:
#include <stdio.h>
#include <string.h>
void zip_strings(const char *a, const char *b) {
size_t combined_length = strlen(a) + strlen(b);
char joined_string[combined_length + 1];
for (size_t i = 0; i < combined_length; i++) {
const char **src = i & 1 ? &b : &a;
if (!**src)
src = &a;
if (!**src)
src = &b;
joined_string[i] = *((*src)++);
}
joined_string[combined_length] = '\0';
puts(joined_string);
}
int main(int argc, char **argv) {
if (argc > 2)
zip_strings(argv[1], argv[2]);
}
./a.out hello computer
hceolmlpouter
I'm trying to dynamically allocate memory for an array of strings, but I'm suffering a segmentation fault. If you can show me some ways to do it, that would be really helpful.
My knowledge so far is that char* is a string, and char** is a two-dimensional array of strings.
If s[i] is a string, shouldn't *(s + i) also be the same thing? I am confused about the topic.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int n;
int main(void)
{
scanf("%i", &n); //number of strings being inputted
char **s = calloc(n, 10 * (sizeof(char) + 1));
for (int i = 0; i < n; i++) //get strings
{
fgets(*(s + i), 10 * (sizeof(char) + 1), stdin);
}
for (int i = 0; i < n; i++) //print the strings
{
fputs(*(s + i), stdout);
}
return 0;
}
In this declaration
char **s = calloc(n, 10 * (sizeof(char) + 1));
you allocated a memory the address of which is assigned to the pointer s. The memory was zero-initialized due to calling the function calloc.
So in this statement
fgets(*(s + i), 10 * (sizeof(char) + 1), stdin);
the pointer s is dereferenced and either is a null pointer (because the pointed memory was zero-initialized) or has an indeterminate value if the expression s + i points outside the allocated memory.
You need to allocate an array of pointers of the type char * and assign to each pointer the address of an allocated array of characters.
Also in general you should check the return value of a call of calloc or malloc.
There is another problem with your code. After the call of scanf
scanf("%i", &n); //number of strings being inputted
the input buffer contains the new line character '\n' that will be read by the following call of fgets. So the first call of fgets will read in fact an empty string.
Another problem is that you should remove the new line character that can be appended to the read string by fgets. For example some read string can contain the new .line character while others can be without it depending on how many characters the user typed.
If you want to write the program without using the subscript operator with pointers then it can look for example the following way.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
size_t n = 0;
if ( scanf( "%zu", &n ) == 1 )
{
scanf( "%*[^\n]" );
scanf( "%*c" );
}
char **s = NULL;
if ( n != 0 ) s = calloc( n, sizeof( char * ) );
if ( s != NULL )
{
size_t len = 11;
size_t m = 0;
while ( m < n && ( *( s + m ) = malloc( len * sizeof( char ) ) ) != NULL ) m++;
size_t i = 0;
while ( i < m && fgets( *( s + i ), len, stdin ) != NULL ) i++;
m = i;
for ( i = 0; i < m; i++ ) //print the strings
{
( *( s + i ) )[ strcspn( *( s + i ), "\n" )] = '\0';
// or without the subscript operator
// *( *( s + i ) + strcspn( *( s + i ), "\n" ) ) = '\0';
puts( *( s + i ) );
}
for ( i = 0; i < n; i++ ) free( *( s + i ) );
}
free( s );
return 0;
}
The program output might look like
10
one
two
three
four
five
six
seven
eight
nine
ten
one
two
three
four
five
six
seven
eight
nine
ten
scanf("%i", &n); //number of strings being inputted
is incomplete, since scanf(3) can fail (e.g. if your user enters hello). You need to add more code checking that scanf was successful. I suggest:
if (scanf("%i", &n) < 0) {
perror("number of strings expected");
exit(EXIT_FAILURE);
}
Then
char **s = calloc(n, 10 * (sizeof(char) + 1));
is wrong. Each element of the array is a char*, which on most machines has 4 or 8 bytes (the sizeof(void*)).
So replace it with
char **s = calloc(n, sizeof(char*));
or with the equivalent char**s = calloc(n, sizeof(*s)); which in my opinion is less readable.
Also, calloc can fail. You need to add a test, like
if (s == NULL) {
perror("calloc of s");
exit(EXIT_FAILURE);
}
Read carefully the documentation of each function (like calloc, fgets etc...) which you did not wrote in this C reference.
The next step should be a loop filling each element of s. With another calloc, or some call to strdup(3) if your system provides it. Of course, that calloc (or strdup) can also fail and you need to test against failure.
You could also use getline(3) (or even readline(3)) if your system has it. Check with your manager if you are legally and technically allowed to use them.
If your compiler is GCC, invoke it with all warnings and debug info: gcc -Wall -Wextra -g. Once you have no warnings, use a debugger like GDB to understand the behavior of your executable.
Consider also using the Clang static analyzer (after getting permission to use it).
Draw on board (or on paper) a figure with arrows representing pointers (like the doubly linked-list figure on wikipedia) to understand the behavior of your program.
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"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char **wordlist=(char **)malloc(sizeof(char*)*4);
for(int i=0;i<4;i++)
{
char *word=(char*)malloc(sizeof(char*)*20);;
scanf("%s",word);
wordlist[i]=word;
free(word);
}
for(int i=0;i<4;i++)
{
printf("at %d value is %s\n",i,wordlist[i]);
}
free(wordlist);
return 0;
}
So the issue is as follows: I can run this code as many times as I want, and when it reads back the array I get COMPLETELY random results when it comes to where things are stored. Example: If input was "foo bar is great" it would output any combination of the following "value at 0 is bar value at 1 is bar value at 2 is great value at 3 is foo"
Part of a much larger program, but this is the concept i'm struggling to find a solution (or proper implementation) to. :( I have searched google high and low, as well as this site, with no solution that works properly. Any help is appreciated!
The program is wrong and has memory leaks.
For example in this statement
char *word=(char*)malloc(sizeof(char*)*20);;
^^^^^^^^^^^^^
there is used sizeof( char * ) instead of sizeof( char )
Then after these statements
wordlist[i]=word;
free(word);
wordlist[I] will point to memory that was deleted.
As result the program has undefined behavior.
What you need is something like the following
#include <stdio.h>
#include <stdlib.h>
#define N 4
#define M 20
int main( void )
{
char ( *wordlist )[M] = malloc( sizeof( char[N][M] ) );
for ( size_t i = 0; i < N; i++ )
{
scanf( "%19s", wordlist[i] );
}
for ( size_t i = 0; i < N; i++ )
{
printf( "at %zu value is %s\n", i, wordlist[i] );
}
free( wordlist );
return 0;
}
For example if to enter
one two free four
then the output will look like
at 0 value is one
at 1 value is two
at 2 value is free
at 3 value is four
Take into account that if your compiler supports variable length arrays then there is not necessary that the right-most dimension would be a constant.
Another approach is to allocate dynamically an array of pointers to first elements of one-dimensional character arrays.
For example
#include <stdio.h>
#include <stdlib.h>
#define N 4
#define M 20
int main( void )
{
char **wordlist = malloc( sizeof( char *[N] ) );
for ( size_t i = 0; i < N; i++ )
{
wordlist[i] = malloc( sizeof( char[M] ) );
scanf( "%19s", wordlist[i] );
}
for ( size_t i = 0; i < N; i++ )
{
printf( "at %zu value is %s\n", i, wordlist[i] );
}
for ( size_t i = 0; i < N; i++ ) free( wordlist[i] );
free( wordlist );
return 0;
}
The result will be the same as for the preceding program. However in this case instead to allocate only one two-dimensional array there are allocated several one-dimensional arrays.
You free each one of your words before actually printing it.
What you need to do is in the end(that is after the priniting -could be in the printing loop)
for (i=0;i<4;i++)
free(wordlist[i]);
free(wordlist)
and remove free(word); in the first loop
I just want you to ask what did I do wrong with this code.
I wrote a function that take a char* in parameter, I want to modify it directly without returning smthg, and reverse the string.
#include <iostream>
void reverseString(char *p_string){
int length = strlen(p_string);
int r_it = length - 1;
char* tmp = (char*)malloc(length);
int last_it = 0;
for (int i = 0; i != length; i++){
tmp[i] = p_string[r_it];
r_it--;
last_it++;
}
tmp[last_it] = '\0';
strcpy_s(p_string, length + 1, tmp);
//free(tmp);
}
int main(){
char str[] = "StackOverflow";
reverseString(str);
std::cout << str << std::endl;
system("pause");
}
I'm used to C++ and don't often use C functions like malloc/free/strcpy...
Here, my problem is, when I alloc memory for my temporary char, I called mallec(length) for length = 13 in this case, char = 1 bytes so it should be allocate memory for 13 char is that right?
Problem is allocate more space than need so i need to use '\0' before my strcpy_s if not it breaks.
Did I do a mistake somewhere?
Also, when i call free(tmp), it breaks too and say heap corruption, but I didn't free the memory before that.
Thanks for helping !
I took your original code and added a simple '+1' to the size of the malloc and got a passing result.
Not sure if your exercise is related specifically to the use of malloc, but have you considered doing the reversal directly inside the original string?
For example:
void reverseString(char *p_string){
char* p_end = p_string+strlen(p_string)-1;
char t;
while (p_end > p_string)
{
t = *p_end;
*p_end-- = *p_string;
*p_string++ = t;
}
}
int main(){
char str[] = "StackOverflow";
reverseString(str);
std::cout << str << std::endl;
system("pause");
}
If you are required to use malloc, then you need to ensure that you allocate enough space for string which includes the '\0'
You must use
int length = strlen(p_string);
int r_it = length - 1;
char* tmp = (char*)malloc(length+1);
Since strlen doesn't count the \0 character. So this will fail if you don't use length+1:
tmp[last_it] = '\0';
The length of a C string is determined by the terminating
null-character: A C string is as long as the number of characters
between the beginning of the string and the terminating null character
(without including the terminating null character itself).
http://www.cplusplus.com/reference/cstring/strlen/
Btw. C99 support semi dynamic arrays. So could you try this:
char tmp[length+1];
Source:
http://en.wikipedia.org/wiki/Variable-length_array
float read_and_process(int n)
{
float vals[n];
for (int i = 0; i < n; i++)
vals[i] = read_val();
return process(vals, n);
}
Check the below C code:
The memory allocated to tmp should be length+1 as done below and also there are many unnecessary variables which can be avoided.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void reverseString(char *p_string){
int i;
int length = strlen(p_string);
int r_it = length - 1;
char* tmp = (char*)malloc(length+1);
for (i = 0; i != length; i++){
tmp[i] = p_string[r_it--];
}
tmp[i] = '\0';
strcpy(p_string, tmp);
return;
}
int main(){
char str[] = "StackOverflow";
reverseString(str);
printf("%s",str);
return 0;
}
There is nothing fundamentally wrong with your approach, just some of the details. Since I am not sure how you found out that the sizeof(tmp) is 32, I modified your code to the one below which includes a few printfs and some minor changes:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void reverseString(char *p_string)
{
size_t length = strlen(p_string);
size_t r_it = length - 1;
char* tmp = (char*)malloc(length+1);
int last_it = 0;
size_t i=0;
printf("strlen(p_string) = %d\n", strlen(p_string));
printf("Before: strlen(tmp) = %d\n", strlen(tmp));
for (i = 0; i != length; i++) {
tmp[i] = p_string[r_it];
r_it--;
last_it++;
}
tmp[last_it] = '\0';
printf("After: strlen(tmp) = %d\n", strlen(tmp));
strcpy(p_string, tmp);
free(tmp);
}
int main()
{
char str[] = "StackOverflow";
reverseString(str);
printf("%s\n", str);
return 0;
}
First, I have removed all C++ specific code - you can now compile this with gcc. Running this code yields this output:
sizeof(p_string) = 13
Before: strlen(tmp) = 0
After: strlen(tmp) = 13
wolfrevOkcatS
This is to be expected - strlen basically counts bytes until it hits the \0 character and so the first time we print the size using strlen, it returns 0 since we just allocated the memory. As another poster suggested, we have to allocate 1 extra byte to store the \0 in our new string.
Once the reverse is complete, 13 bytes would have been copied over to this memory and the second strlen returns the expected answer.