HackerRank staircase C confusion - c

Hi i'm pretty new and trying to improve through hackerrank, i am on the staircase excercise staircase excercise
However my output is different to the question, as it seems my staircase has a extra space infront of the result thus making it incorrect. here is my code.
#include <stdio.h>
int main ()
{
int size = 0;
//input size of staircase
scanf("%d" , &size);
//create array to hold staircase
char list [size];
//iterate through and fill up array with spaces
for (int i = 0; i <size; ++i)
{
list[i] = ' ';
}
//the iterate backwards -1 each time replacing each spcae with a '#' and printing each stair case starting from smallest at the top.
for (int i = size; i >0; i--)
{
list[i] = '#';
printf("%s\n", list);
}
return 0;
}
I am confused as to what the problem is and why there is my staircase more spaced out than the expected question? i've been trying to work it out, and any help is really much needed.
My output:
#
##
###
####
#####
######
*EDIT - thanks for the help, all the answers were helpful.

There are several mistakes:
1) You forgot to put a null character ('\0') at the end of the string. Do this:
for (int i = 0; i <size; ++i)
{
list[i] = ' ';
}
list[i] ='\0';
2)
for (int i = size; i >0; i--)
{
list[i] = '#';
printf("%s\n", list);
}
Here the index you are trying to access for the string is invalid (when i=size). Do like this:
for (int i = size-1; i > -1; i--)
{
list[i] = '#';
printf("%s\n", list);
}

An array of length size is indexed from 0 to size - 1:
E.g. for size == 4:
[0][1][2][3]
In your second loop you go from size to 1, first writing outside the array, and finally leaving the first entry untouched:
[ ][#][#][#] #
You must either change your second loop to
for (int i = size - 1; i >= 0; i--)
or alternatively do
list[i - 1] = '#';
instead of list[i] = '#'.

Related

Cunit test invalid read/write of size8

Invalid read and write of size 8 happening in modify_tab_size().
what am I doing wrong? Ive tried almost everything, I dont understand it.
// Function being tested.
int erase_repeated(int *nb_words, char **words) {
for (int i = 0; i < *nb_words; ++i) {
if (words[i] != 0) {
for (int b = 0; b < *nb_words; ++b) {
if (strcmp(words[i], words[b]) == 0 && b != i)
modify_tab_size(&b, nb_words, words);
}
}
}
return *nb_mots;
}
void modify_tab_size(int *b, int *nb_words_update, char **words) {
free(words[*b]);
for (int k = *b; k < *nb_words_update; k++) {
words[k] = words[k + 1]; <--------------------------read error
words[*nb_words_update + 1] = 0; <--------------------------write error
}
(*nb_words_update)--;
(*b)--;
}
The problem is k+1 and *nb_words_update + 1 can walk off the array, and it is. Add printf("k:%d, k+1:%d, *nb_words_update + 1: %d\n", k, k+1, *nb_words_update + 1); into the loop to see.
k:1, k+1:2, *nb_words_update + 1: 4
k:2, k+1:3, *nb_words_update + 1: 4
You've only allocated three slots, 3 and 4 walk off the end of the array.
Since nb_words_update starts as the length of the array, words[*nb_words_update + 1] = 0; is always going to be too large. words[*nb_words_update] = 0; is also too large.
What you seem to be trying to do is deleting an element from an array by shifting everything after it to the left.
void delete_element(char **words, int *b, int *size) {
// Free the string to be deleted.
free(words[*b]);
// Only go up to the second to last element to avoid walking off the array.
for (int i = *b; i < *size-1; i++) {
// Shift everything to the left.
words[i] = words[i+1];
}
// Null out the last element.
// Don't use 0 for NULL, it's confusing.
words[*size-1] = NULL;
// Decrement the size of the array.
(*size)--;
// Redo the check with the newly shifted element.
(*b)--;
}
This sort of thing is better done with a linked list.
Note that your code has a bug. The result is an array of two elements, but one of them is blank. In addition to the return value of erase_repeated, also test its side effect which is to modify words. Test that words contains what you think it does.

Split character array into multiple parts

In C, how would I go about splitting a char array into multiple parts, then back into an array. I am looking to split into 10 parts. But to make sure when it's split, it's split at a space and not by the character count.
I would like to be able to split it into another array so I can just call the index for each of them. But I am rather new to C/C++. In Java, I assume I could create an Array and then call array[0]-array[9] to get the split values after the operation is complete.
I would have:
char *s1 = "An example array that can be present right here. With a lot more words than this. But this is just an example after all. So does it really matter currently?"
And would need to be split into 10 parts (doesn't need to be equal in length) but just in 10 semi-equal parts.
So there are two parts to this:
a function that can find the closest space character to the next split point
a function that finds the next wrap point and saves the resulting string
For the first function, we need to pass in the string, its size, the last wrap point, and the next potential wrap point. It needs to return the next actual wrap point. So the function will have a definition like this:
int wrappoint(const char *string, int size, int previous, int current);
To find the next wrap point we need to search for a space character from the current wrap point both forward (until the end of the string) and backward (until the previous wrap point):
int before=-1, after=-1;
for(int i=current; i>previous; i--)
if(string[i] == ' ')
{ before = i; break; }
for(int i=current; i<=size; i++)
if(string[i] == ' ')
{ after = i; break; }
At this point before and after will contain the indices of the nearest space characters - or -1 if a space was not found i nthat direction. Then we just need to return a valid next wrap point based on what we found:
if(before==-1 && after==-1)
return size;
else if(before==-1)
return after;
else if(after==-1)
return before;
else if(current-before < after-current)
return before;
else
return after;
For the second function, we can just pass the string and the number of parts. The function will dynamically allocate an array big enough to hold all the parts. Each array index will be a pointer to a dynamically allocated string. Then the function can return the array and it will be the caller's responsibility to free all that memory. So the function will have a definition like this:
char **split(const char *string, int parts) {
The first thing we need to do is find the length of the string and make an array to hold all the parts. We use calloc so that any indices we don't use will be set to NULL:
char **array = calloc(parts, sizeof(char *));
int size = strlen(string);
Then we have to loop through the string, calling the wrappoint function to find the start and end of each part, allocating space for that part and then copying that part into the array:
int previous = 0, current = 0;
for(int i = 0; i < parts && current < size; i++) {
current = wrappoint(string, size, previous, previous+size/parts);
array[i] = malloc(current-previous+1);
strncpy(array[i], string+previous, current-previous);
array[i][current-previous] = '\0';
previous = current+1;
}
Then we can call split, which returns an array containing the parts - but some of them might be NULL if there are fewer spaces in the string than the number of parts we asked for. We can display the array of parts like this:
for(int i=0; i<10 && array[i]; i++)
printf("%d: %s\n", i, array[i]);
And then when we are done we have to free all the memory that split allocated:
for(int i=0; i<10 && array[i]; i++)
free(array[i]);
free(array);
Here is the full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int wrappoint(const char *string, int size, int previous, int current) {
int before=-1, after=-1;
for(int i=current; i>previous; i--)
if(string[i] == ' ')
{ before = i; break; }
for(int i=current; i<=size; i++)
if(string[i] == ' ')
{ after = i; break; }
if(before==-1 && after==-1)
return size;
else if(before==-1)
return after;
else if(after==-1)
return before;
else if(current-before < after-current)
return before;
else
return after;
}
char **split(const char *string, int parts) {
char **array = calloc(parts, sizeof(char *));
int size = strlen(string);
int previous = 0, current = 0;
for(int i = 0; i < parts && current < size; i++) {
current = wrappoint(string, size, previous, previous+size/parts);
array[i] = malloc(current-previous+1);
strncpy(array[i], string+previous, current-previous);
array[i][current-previous] = '\0';
previous = current+1;
}
return array;
}
int main() {
char *string = "An example array that can be present right here. With a lot more words than this. But this is just an example after all. So does it really matter currently?";
char **array = split(string,10);
for(int i=0; i<10 && array[i]; i++)
printf("%d: %s\n", i, array[i]);
for(int i=0; i<10 && array[i]; i++)
free(array[i]);
free(array);
return 0;
}
Try it at https://onlinegdb.com/uoDzM2toi
This example string:
An example array that can be present right here. With a lot more words than this. But this is just an example after all. So does it really matter currently?
Produces this output:
0: An example array
1: that can be present
2: right here. With
3: a lot more words
4: than this. But
5: this is just an
6: example after
7: all. So does it
8: really matter
9: currently?

print list and separate values by a comma comma and end with a dot

printf("Open lockers: ");
for(int i = 0; i < sizeof(lockers); i++){
if (lockers[i] == true){
if(i == sizeof(lockers) - 1){
printf(" %d.", i +1);
}else
printf(" %d,", i +1);
}
}
//This is what i got but it doesn't work for when i change list size
I would approach this by maintaining some additional state which keeps track of whether or not it is the first open locker which needs to be reported. And then, just print period outside the loop, only once.
printf("Open lockers: ");
int first = 1;
for (int i=0; i < sizeof(lockers); i++) {
if (lockers[i] == true) {
if (first == 0) {
printf(", ");
}
else {
first = 0;
}
printf("%d", i + 1);
}
}
printf(".");
Demo
Note: In the demo I replaced your bool lockers array with an int array. But the rest of the logic remains the same.
One option is to use a variable like pad in this code:
const char *pad = "";
printf("Open lockers:");
for (int i = 0; i < sizeof(lockers); i++)
{
if (lockers[i])
{
printf("%s %d", pad, i + 1);
pad = ",";
}
}
putchar('.');
Another variant is:
const char *pad = ":";
printf("Open lockers");
for (int i = 0; i < sizeof(lockers); i++)
{
if (lockers[i])
{
printf("%s %d", pad, i + 1);
pad = ",";
}
}
putchar('.');
Note that sizeof(lockers) only works if sizeof(lockers[0]) == 1. I left it because that's what you used, but I'd normally have a variable set to the maximum value and use that in the loop.
Your loop condition is probably wrong
for(int i = 0; i < sizeof(lockers); i++){
if (lockers[i] == true){
You do not show us, what lockers is. As you use it with an index it could be an array or a pointer to an array.
If lockers is an array, sizeof will result in the size in bytes. Unless the elements are of type char, you will end up accessing the array beyond its allocated memory.
You can get the number of elements using sizeof(array)/sizeof(array[0]).
int lockers[10];
With a definition like that you would access 40 integer elements whily you only have 10.
If lockers is a pointer to an array, sizeof will only result in the size of a pointer (probably 4 or 8 bytes) and you will not access all elements of your array where your pointer points to if the array has more elements than 4 or 8.
int *lockers = malloc(20 * sizeof(int));
With a definition like that you would only access 1 or 2 elements instead of 20.
Update:
In the comments I found the missing information. It would help a lot if you put it into the question instead of comments.
You are lucky, sizeof(lockers[i]) is 1 which will work for your loop.

Searching for block of characters (word) in a text

I want to search for a block of characters (word) in a text.
For example, I have the next text "Hello xyz world", and I want to search for "xyz ", note the space after the word.
// The Text
const char * text = "Hello xyz world";
// The target word
const char * patt = "xyz ";
size_t textLen = strlen(text),
pattLen = strlen(patt), i, j;
for (i = 0; i < textLen; i++) {
printf("%c", text[i]);
for (j = 0; j < pattLen; j++) {
if (text[i] == patt[j]) {
printf(" <--");
break;
}
}
printf("\n");
}
The result must be like following:
But unfortunately, the result as the following:
It collects all the similar characters in the whole text, not just the target characters (the word).
How to fix that problem?
You have to do a full substring match before you print; mark the applicable characters on a first pass, and then have a second pass to print the results. In your case, you'd create a second array, with boolean values corresponding to the first, something like
text = "Hello xyz world";
match 000000111100000
I assume that you can find a basic substring match program online. Printing on the second pass will be easy: you already have the logic. Instead of if (text[i] == patt[j]), just use if match[i].
Is that enough of a hint?
You need to make sure that there is a full match before starting to print any <--. And to avoid to do accesses passed end of array on patt, you will have to stop searching when less than pattLen characters remain in array.
Then when you have found a full match, you can print the content of patt followed with <-- and increment position of pointer of pattLen-1. And at the end you will have to copy remaining characters from text.
Code could become:
// The Text
const char * text = "Hello xyz world";
// The target word
const char * patt = "xyz ";
size_t textLen = strlen(text),
pattLen = strlen(patt), i, j;
for (i = 0; i <= textLen - pattLen; i++) { // don't search if less that pattLen remains
printf("%c", text[i]);
if (text[i] == patt[0]) { // first char matches
int found = 1; // be optimistic...
for (j = 1; j < pattLen; j++) {
if (patt[j] != text[i + j]) {
found = 0;
break; // does not fully match, go on
}
}
if (found) { // yeah, a full match!
printf(" <--"); // already printed first char
for (j = 1; j < pattLen; j++) {
printf("\n%c <--", patt[j]);// print all others chars from patt
}
i += pattLen - 1; // increase index...
}
}
printf("\n");
}
while (i < textLen) {
printf("%c\n", text[i++]); // process the end of text
}
Above code gives expected output for "xyz " and also "llo"...
You should check every letter of your pattern from the beginning (and not check the whole pattern). Try this (not tested):
int currIndex = 0;
for (i = 0; i < textLen; i++) {
printf("%c", text[i]);
if (text[i] == patt[currIndex]) {
for (j = 0; j < pattLen; j++) {
if(text[i+j] != patt[j]){
continue;
}
}
printf(" <--");
currIndex++;
if(currIndex==pattLen)
currIndex = 0;
}
else{
currIndex = 0;
}
printf("\n");
}
Note: It is not the best way to achieve this but the easiest with your example
Note 2: This question should be closed as it is:
Questions seeking debugging help ("why isn't this code working?") must
include the desired behavior, a specific problem or error and the
shortest code necessary to reproduce it in the question itself.
Questions without a clear problem statement are not useful to other
readers. See: How to create a Minimal, Complete, and Verifiable
example.

Problems with creating a function to reverse a string [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 7 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
I need to create a fuction that returns a string. So far I have come up with this code:
#include <stdio.h>
#include <string.h>
#define SIZE 256
void str_reverse(char[SIZE], char[SIZE]);
int main(void)
{
char input[SIZE];
char output[SIZE];
printf("Please enter a string\n");
fgets(input, SIZE, stdin);
str_reverse(input, output);
printf("%s \n", output);
return 0;
}
void str_reverse(char in[SIZE], char out[SIZE])
{
int i = strlen(in);
int k = 0;
for(int j = i; j>= 0; j--)
{
out[k] = in[j];
k++;
}
}
However, whenever I try to run the code, I do not get an output. Does anyone have any idea what could be wrong
The problem is this line
int i = strlen(in);
Change it to
int i = strlen(in)-1;
strlen() returns the size of the string, hence when you start copying from in[], in[j] would be \0. which is getting stored in out[0].
Another change you need to do is put a \0 in the out[], just after the for loop
for(int j = i; j>= 0; j--)
{
out[k] = in[j];
k++;
}
out[k] = '\0';
Your "reversing" includes the null character too. So the reversed string's first character is '\0'. So the string is empty.
Change:
for(int j = i ; j>= 0; j--)
to
for(int j = i - 1; j>= 0; j--)
You should also check if the string length is zero before the for loop. Otherwise, i-1 will become SIZE_MAX and you'll have problems with that!
A simple condition such as the following in str_reverse() would handle that case:
size_t i = strlen(in);
int k = 0;
if (i<=1) return; //empty string or contains only 1 char char.
i starts out at strlen(in), so the first character you copy over tooutis the null byte at the end of the string. Every other character then appears after the null terminator, soout` is an empty string.
Start with i at strlen(in) - 1, then add the null terminator and the end of the loop:
int i = strlen(in) - 1; // start at the last non-null character
int k = 0;
for(int j = i; j>= 0; j--)
{
out[k] = in[j];
k++;
}
out[k] = '\0'; // add the null terminator
When k is 0 and j is i, you do the following:
out[0] = '\0';
Hence, out looks like an empty string when the function returns.
Use:
for(int j = i-1; j>= 0; j--)
{
out[k] = in[j];
k++;
}
out[k] = '\0';
In the function variable i is set the following way
int i = strlen(in);
So within the loop
for(int j = i; j>= 0; j--)
{
out[k] = in[j];
k++;
}
then j is equal to i then in[j] is equal to the terminating zero '\0' of string in. Thus array out starts from zero that is it will contain an empty string.
It is better to declare the function itself the following way
char * str_reverse( char *out, const char *in );
and to return from the function the pointer out. In this case you could write for example
puts( str_reverse( output, input ) );
Take into acount that function fgets usually also stores the new line character in the string. You should remove it. you can do it the following way
input[strcspn( input, "\n" )] = '\0';
Also instead of the type int in this statement
int i = strlen(in);
it is better to use type size_t.
size_t i = strlen(in);
It is the type of the return value of the function strlen. But in this case you should also to write the loop correctly.:)

Resources