I am working on a problem for CS50 in which I must create a pyramid out of #'s based on user input of a height. Here is what I have so far, but for height of 8, it only iterates once. For height of 7, I get about four lines of just a mess of #'s.
//Create GetPosInt() function
int GetPosInt(void) {
int n = GetInt();
while (n <= 0) {
printf("That won't work...\nRetry: ");
n = GetInt();
}
return n;
}
int main(void) {
printf("How high should Mario's pyramid be?\nHeight: ");
int h = GetPosInt();
while (h > 23) {
printf("Try something smaller!\nHeight: ");
h = GetPosInt();
}
char str[] = "##";
char strad[] = "#";
int l = h + 1;
for (int i = 0; i < h; i++) {
printf("%*s\n", l, str);
strcat(str, strad);
return 0;
}
}
This is my first attempt with the string.h library.
Please only tips on fixing my code - I'm certain there are other ways about it, but if it's possible this way, I'd like to keep it so for the class!
Your str array/C-String has no room to concatenate other chars than 2 chars.
As a little change you could do:
char str[128] = "";
strcat(str, "##");
Your return 0; is inside the loop, hence why. Edit as so:
for (int i = 0; i < h; i++) {
printf("%*s\n", l, str);
strcat(str, strad);
}
return 0;
In the C programming language you have to manage memory yourself. These memory allocations will not expand when you use strcat. Instead you will override memory beyond the memory allocated for str. I strongly suggest you first do an introduction into programming in C and how to manage memory manually.
You should return after the loop. You are leaving the function as soon as the first iteration finishes.
Also you should try defining str as :
char * str;
str = malloc( sizeof(char)* 2);
str = strcat(str, "##");
And using strcat as : str = strcat(str,strad);
Related
I'm trying to do a program that get number of names from the user, then it get the names from the user and save them in array in strings. After it, it sort the names in the array by abc and then print the names ordered. The program work good, but the problem is when I try to free the dynamic memory I defined.
Here is the code:
#include <stdio.h>
#include <string.h>
#define STR_LEN 51
void myFgets(char str[], int n);
void sortString(char** arr, int numberOfStrings);
int main(void)
{
int i = 0, numberOfFriends = 0, sizeOfMemory = 0;
char name[STR_LEN] = { 0 };
char** arrOfNames = (char*)malloc(sizeof(int) * sizeOfMemory);
printf("Enter number of friends: ");
scanf("%d", &numberOfFriends);
getchar();
for (i = 0; i < numberOfFriends; i++) // In this loop we save the names into the array.
{
printf("Enter name of friend %d: ", i + 1);
myFgets(name, STR_LEN); // Get the name from the user.
sizeOfMemory += 1;
arrOfNames = (char*)realloc(arrOfNames, sizeof(int) * sizeOfMemory); // Change the size of the memory to more place to pointer from the last time.
arrOfNames[i] = (char*)malloc(sizeof(char) * strlen(name) + 1); // Set dynamic size to the name.
*(arrOfNames[i]) = '\0'; // We remove the string in the currnet name.
strncat(arrOfNames[i], name, strlen(name) + 1); // Then, we save the name of the user into the string.
}
sortString(arrOfNames, numberOfFriends); // We use this function to sort the array.
for (i = 0; i < numberOfFriends; i++)
{
printf("Friend %d: %s\n", i + 1, arrOfNames[i]);
}
for (i = 0; i < numberOfFriends; i++)
{
free(arrOfNames[i]);
}
free(arrOfNames);
getchar();
return 0;
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char str[], int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
/*In this function we get array of strings and sort the array by abc.
Input: The array and the long.
Output: None*/
void sortString(char** arr, int numberOfStrings)
{
int i = 0, x = 0;
char tmp[STR_LEN] = { 0 };
for (i = 0; i < numberOfStrings; i++) // In this loop we run on all the indexes of the array. From the first string to the last.
{
for (x = i + 1; x < numberOfStrings; x++) // In this loop we run on the next indexes and check if is there smaller string than the currnet.
{
if (strcmp(arr[i], arr[x]) > 0) // If the original string is bigger than the currnet string.
{
strncat(tmp, arr[i], strlen(arr[i])); // Save the original string to temp string.
// Switch between the orginal to the smaller string.
arr[i][0] = '\0';
strncat(arr[i], arr[x], strlen(arr[x]));
arr[x][0] = '\0';
strncat(arr[x], tmp, strlen(tmp));
tmp[0] = '\0';
}
}
}
}
After the print of the names, when I want to free the names and the array, in the first try to free, I get an error of: "HEAP CORRUPTION DETECTED: after normal block(#87)". By the way, I get this error only when I enter 4 or more players. If I enter 3 or less players, the program work properly.
Why does that happen and what I should do to fix it?
First of all remove the unnecessary (and partly wrong) casts of the return value of malloc and realloc. In other words: replace (char*)malloc(... with malloc(..., and the same for realloc.
Then there is a big problem here: realloc(arrOfNames, sizeof(int) * sizeOfMemory) : you want to allocate an array of pointers not an array of int and the size of a pointer may or may not be the same as the size of an int. You need sizeof(char**) or rather the less error prone sizeof(*arrOfNames) here.
Furthermore this in too convoluted (but not actually wrong):
*(arrOfNames[i]) = '\0';
strncat(arrOfNames[i], name, strlen(name) + 1);
instead you can simply use this:
strcpy(arrOfNames[i], name);
Same thing in the sort function.
Keep your code simple.
But actually there are more problems in your sort function. You naively swap the contents of the strings (which by the way is inefficient), but the real problem is that if you copy a longer string, say "Walter" into a shorter one, say "Joe", you'll write beyond the end of the allocated memory for "Joe".
Instead of swapping the content of the strings just swap the pointers.
I suggest you take a pencil and a piece of paper and draw the pointers and the memory they point to.
In C, If I have a string assigned to a variable, and I want to change only the last 4 letters in that string for something else, how should I do it? strcat()? Something like:
int size;
char a[10] = "something";
size = strlen(a) - 4;
strcat(a + size, "1234");
Would that work? to get somet1234 ? or would it just be something1234 ?
Use strncpy (to prevent an extra terminator from being appended) to overwrite from a given position:
strncpy(a + size, "1234", 4);
If you really want strcat, cut the string manually for strcat() to find the starting place to concatenate:
a[size] = '\0'; // Cut the string so strcat() know where to start
strcat(a, "1234");
No, that will not work. If you used strcpy() instead of strcat() it would.
public string convertto(string abc,string replacewith,int len)
//something, 1234 and length to replace i-e 4
{
int g = strlen(abc);
int f = g - len;
j=0;
char[] temp =new char[g];
for (int i = 0; i < g; i++)
{
if (i >= f)
{
temp[i] = replaceWith[j];
j++;
}
else
{
temp[i] = abc[i];
}
}
return temp.ToString();
}
// It will return somet....
helloeveryone. I am fairly new to programming and currently trying to learn C programming to advance further in any of my projects. I've just learned how to use malloc and realloc, and all seemed good until I attempted to use strcat to combine two given strings from multidimensional array.
I am supposed to get combination of two strings based on the user inputs, and strangely, the first character is either missing or replaced by other characters...
I'll include the source code as well as the output below. I'd really appreciate you help. Thanks in advance!! ( don't mind the Korean at the end... I am korean :P)
enter code here
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
int i, j;
const int row = 3;
char *pstr[3];
char temp[100];
int k,p = 0;
printf("Type in any three characters\n");
for (i = 0; i < row; i++)
{
pstr[i] = (char *)malloc(strlen(temp) + 1); //initialize the lenght of the elements in 2 part of 2D array of char b[ROW] via length of the given string
}
for (i = 0; i < row; i++)
{
scanf("%s", temp);
strcpy(pstr[i], temp);
}
printf("\n");
for (i = 0; i < row; i++)
{
printf("%s\n", pstr[i]);
}
scanf("%d", &p);
scanf("%d", &k);
printf("%s\n", pstr[p]);
printf("%s\n", pstr[k]);
*pstr[k] = (char *)realloc(pstr[k], strlen(pstr[p])+100);
strcat(pstr[k], pstr[p]);
printf("%s", pstr[k]);
for (i = 0; i < row; i++)
{
free(pstr[i]);
}
return 0;
}
\
output::LINK IS AN INTERNATIONAL SIGN FOR , IMAGE OVER HERE!!!
Two major problems:
You use temp before it have been initialized, when its contents is indeterminate and that will lead to undefined behavior.
When you do *pstr[k] = realloc(...) you dereference the pointer in pstr[k] and gets it's first element, which is a single character. You then assign the result of the realloc call to this char element. So you basically lose the actual pointer and pstr[k] will still point to the same memory (which might now be invalid).
There are other problems, but these two are the worst.
I found these in your code
1) if k or p is greater than 2 it will give runtime error
2) *pstr[k] = (char *)realloc(pstr[k], strlen(pstr[p])+100);
but this line can give error in compile time also(mac at least) - as they are not same
so you may change like this -
*pstr[k] = *(char *)realloc(pstr[k], strlen(pstr[p])+100);
3) After realloc you will get exception in free. see this - How free memory after of realloc
I'm trying to create an array of patterns for a triangle that I'm also printing to the console. I do this by creating a 2d char array where
char patterns [number_of_patterns][pattern_lengths]. I pass this to a function that takes the array patterns along with the height of the triangle I'm trying to make.
void printTriangle (int rows, char rowPatterns[][rows]) {
int initialSpaces = rows - 1;
int numberOfAsterisks = 1;
int i;
for (i = 0; i < rows; i++) {
char temp[rows];
int spaceCounter = 0;
int asteriskCounter = 0;
while (spaceCounter < initialSpaces) {
printf(" ");
sprintf(temp, " ");
spaceCounter++;
}
while (asteriskCounter < numberOfAsterisks) {
sprintf(temp, "*");
printf("*");
asteriskCounter++;
}
while (spaceCounter < initialSpaces) {
spaceCounter = 0;
sprintf(temp, " ");
spaceCounter++;
}
strcpy(rowPatterns[i], temp);
printf("\n");
initialSpaces--;
numberOfAsterisks+=2;
}
}
For every row of the triangle that I'm printing, I create a string for that row called temp. At the end of the for loop that prints the row to the console and sprintf's it to the array temp, I strcpy temp into patterns[i]. Then I go back to the top of the loop, reinitialize temp to make it fresh, and loop again until I have all my rows. Except for some reason sprint won't fill in my array temp. Is this incorrect use of the function, or does it have to do w my parameter passing?
sprintf always writes to the start of the string. To append, you can maintain a pointer to the end of the string:
char *ptr = rowpatterns[i];
ptr += sprintf(ptr, "*");
You might also hear the suggestion to use strcat - avoid that function. When building strings, repeated strcat is very slow and is a common source of performance issues in string code.
I can't write a workable code for a function that deletes N characters from the string S, starting from position P. How you guys would you write such a function?
void remove_substring(char *s, int p, int n) {
int i;
if(n == 0) {
printf("%s", s);
}
for (i = 0; i < p - 1; i++) {
printf("%c", s[i]);
}
for (i = strlen(s) - n; i < strlen(s); i++) {
printf("%c", s[i]);
}
}
Example:
s: "abcdefghi"
p: 4
n: 3
output:
abcghi
But for a case like n = 0 and p = 1 it's not working!
Thanks a lot!
A few people have shown you how to do this, but most of their solutions are highly condensed, use standard library functions or simply don't explain what's going on. Here's a version that includes not only some very basic error checking but some explanation of what's happening:
void remove_substr(char *s, size_t p, size_t n)
{
// p is 1-indexed for some reason... adjust it.
p--;
// ensure that we're not being asked to access
// memory past the current end of the string.
// Note that if p is already past the end of
// string then p + n will, necessarily, also be
// past the end of the string so this one check
// is sufficient.
if(p + n >= strlen(s))
return;
// Offset n to account for the data we will be
// skipping.
n += p;
// We copy one character at a time until we
// find the end-of-string character
while(s[n] != 0)
s[p++] = s[n++];
// And make sure our string is properly terminated.
s[p] = 0;
}
One caveat to watch out for: please don't call this function like this:
remove_substr("abcdefghi", 4, 3);
Or like this:
char *s = "abcdefghi";
remove_substr(s, 4, 3);
Doing so will result in undefined behavior, as string literals are read-only and modifying them is not allowed by the standard.
Strictly speaking, you didn't implement a removal of a substring: your code prints the original string with a range of characters removed.
Another thing to note is that according to your example, the index p is one-based, not zero-based like it is in C. Otherwise the output for "abcdefghi", 4, 3 would have been "abcdhi", not "abcghi".
With this in mind, let's make some changes. First, your math is a little off: the last loop should look like this:
for (i = p+n-1; i < strlen(s); i++) {
printf("%c", s[i]);
}
Demo on ideone.
If you would like to use C's zero-based indexing scheme, change your loops as follows:
for (i = 0; i < p; i++) {
printf("%c", s[i]);
}
for (i = p+n; i < strlen(s); i++) {
printf("%c", s[i]);
}
In addition, you should return from the if at the top, or add an else:
if(n == 0) {
printf("%s", s);
return;
}
or
if(n == 0) {
printf("%s", s);
} else {
// The rest of your code here
...
}
or remove the if altogether: it's only an optimization, your code is going to work fine without it, too.
Currently, you code would print the original string twice when n is 0.
If you would like to make your code remove the substring and return a result, you need to allocate the result, and replace printing with copying, like this:
char *remove_substring(char *s, int p, int n) {
// You need to do some checking before calling malloc
if (n == 0) return s;
size_t len = strlen(s);
if (n < 0 || p < 0 || p+n > len) return NULL;
size_t rlen = len-n+1;
char *res = malloc(rlen);
if (res == NULL) return NULL;
char *pt = res;
// Now let's use the two familiar loops,
// except printf("%c"...) will be replaced with *p++ = ...
for (int i = 0; i < p; i++) {
*pt++ = s[i];
}
for (int i = p+n; i < strlen(s); i++) {
*pt++ = s[i];
}
*pt='\0';
return res;
}
Note that this new version of your code returns dynamically allocated memory, which needs to be freed after use.
Here is a demo of this modified version on ideone.
Try copying the first part of the string, then the second
char result[10];
const char input[] = "abcdefg";
int n = 3;
int p = 4;
strncpy(result, input, p);
strncpy(result+p, input+p+n, length(input)-p-n);
printf("%s", result);
If you are looking to do this without the use of functions like strcpy or strncpy (which I see you said in a comment) then use a similar approach to how strcpy (or at least one possible variant) works under the hood:
void strnewcpy(char *dest, char *origin, int n, int p) {
while(p-- && *dest++ = *origin++)
;
origin += n;
while(*dest++ = *origin++)
;
}
metacode:
allocate a buffer for the destination
decalre a pointer s to your source string
advance the pointer "p-1" positions in your source string and copy them on the fly to destination
advance "n" positions
copy rest to destination
What did you try? Doesn't strcpy(s+p, s+p+n) work?
Edit: Fixed to not rely on undefined behaviour in strcpy:
void remove_substring(char *s, int p, int n)
{
p--; // 1 indexed - why?
memmove(s+p, s+p+n, strlen(s) - n);
}
If your heart's really set on it, you can also replace the memmove call with a loop:
char *dst = s + p;
char *src = s + p + n;
for (int i = 0; i < strlen(s) - n; i++)
*dst++ = *src++;
And if you do that, you can strip out the strlen call, too:
while ((*dst++ = *src++) != '\0);
But I'm not sure I recommend compressing it that much.