I'm not sure why malloc is allocating so much space. Here's a snippet of the problem code:
char * hamming_string = NULL;
void enter_params(){
printf("Enter the max length: ");
scanf_s("%d", &max_length);
hamming_string = (char *) malloc(max_length * sizeof(char));
// to test what's going on with the hamming string
for(int i = 0; i < strlen(hamming_string); i++){
hamming_string[i] = 'a';
}
printf("hamming string = %s", hamming_string);
}
I set max_length to 2 and I'm seeing 12 a's. In another function, I was going to have the user input the hamming string using scanf_s("%s", &hamming_string); but I kept getting a access violation
hamming_string is not a string until one of its elements is a '\0'.
The str*() functions can only be used on strings.
Your program invokes Undefined Behaviour (by calling strlen() with something that is not a string).
malloc() allocates the amount of space that you ask for but it does not initialise it. When you call strlen() it scans the memory starting at what hamming_string points to and continues until it finds a null or it accesses memeory that it shouldn't and causes an exception.
In addition you need to allocate space for the null at the end of the string, if you want a string to hold 2 characters you need to allocate 3 characters to allow for the terminating null.
You are asking for the strlen of an uninitialized variable (this is undefined behaviour):
strlen(hamming_string);
(m)allocate one more in order to store the trailling \0:
hamming_string = malloc(max_length + 1);
change to
for(int i = 0; i < max_length; i++){
hamming_string[i] = 'a';
}
and don't forget to add the trailling \0 after the for loop:
hamming_string[i] = '\0'; /* or use calloc and skip this line */
void check_code(){
int actual_length, parity_bit, error_bit = 0, c = 0, i, j, k;
printf("Enter the Hamming code: ");
scanf_s("%s", &hamming_string);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This scanf_s() call is incorrect.
According to the C11 documentation or MSDN documentation it needs to be
scanf_s("%s", hamming_string, size - 1);
Note that you don't know size inside the function.
Note that you don't pass the address of hamming_string; hamming_string by itself gets converted to the address of its first element.
Example1:
char *hamming_string = malloc((max_length + 1) * sizeof(char));
for (i = 0; i < max_length; i++)
{
hamming_string[i] = 'a';
}
hamming_string[i] = '\0';
printf("hamming string = [%s]\n", hamming_string);
Output:
sdlcb#Goofy-Gen:~/AMD$ ./a.out
hamming string = [aaaaaaaaaaaa]
Example2:
char s;
for (i = 0; i < max_length; i++)
{
scanf(" %c", &s);
hamming_string[i] = s;
}
hamming_string[i] = '\0';
printf("hamming string = [%s]\n", hamming_string);
Output:
sdlcb#Goofy-Gen:~/AMD$ ./a.out
a
b
c
d
e
f
g
h
i
j
k
l
hamming string = [abcdefghijkl]
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.
So I want to write a program which will reverse a string taken from the user.
Here's my source code:
#include <stdio.h>
#include <stdlib.h>
int main(int argv, char *argc[]) {
if (argv != 2) {
printf("Please enter the number of elements in your string!\n");
return 1;
}
int n = atoi(argc[1]);
char *c = malloc((sizeof(char) * n) + 1);
char *o = malloc((sizeof(char) * n) + 1);
printf("Enter your string - ");
fgets(c, n, stdin);
for (int i = 0; i < n + 1; i++) {
*(o + i) = *(c + (n - 1) - i);
}
printf("%s\n", o);
free(c);
free(o);
}
But the printed output is nothing!
Can someone please point out what's wrong with my code?
The issue that prevents the code from working is the missmatch in the size of o and c containers, and the read size in fgets, since fgets null-terminates the string read from input.
So let's say n = 6 as you read your string, fgets replaces the 6th character with a null-terminator, when you reverse it the null-terminator will now be the first character in o, essentially, it will be an empty string, as a string is a null-terminated char-array, or byte-array.
To fix this give fgets the size of your mallocced space.
fgets(c, n + 1, stdin);
And null-terminate o when you are finished reversing.
*(o + n) = '\0';
Or
o[n] = '\0'; //you can use this notation which is more readable than dereferencing
Minor issues:
The fact that you switch the names of main arguments. It normally is int main(int argc, char * argv[]). That can be confusing for someone who reads your code.
char *c = malloc((sizeof(char) * n) + 1); has unnecessary logic, it can be char *c = malloc(n + 1);, a char is one byte in size.
There is an underlying problem with the logic of the program, when the inputed string is shorter than what you ask the user the outupt will not be the desired one, you can make an extra effort bullet-proofing your code for erroneous inputs.
All things considered, taking your code as base, it can be something like:
//Only the changed parts are represented, the rest is the same
#include <string.h> //for strlen
//...
if (argc != 2 || atoi(argv[1]) < 1) { //n must be positive (I switched argv and argc)
printf("Please enter the number of elements in your string!\n");
return 1;
}
size_t n = atoi(argv[1]); //size_t type more suited for sizes
char *c = malloc(n + 1);
char *o = malloc(n + 1);
//...
fgets(c, n + 1, stdin); //as stated n + 1 size argument
if(strlen(c) < n) { //if the length of inputed string is shorter than intended
puts("The string size shorter than stated!");
return 1;
}
//...
for (size_t i = 0; i < n + 1; i++) { //repalced int iterator type whith size_t
//...
o[n] = '\0'; //null terminate o
//...
There are multiple problems in your program:
why do you require an argument for the number of characters? it would be much simpler to assume a maximum length and define char arrays in main() with automatic storage.
the statement char *c = malloc((sizeof(char) * n) + 1); computes the correct allocation size, but by chance because sizeof(char) is always 1. You should write char *c = malloc(n + 1); or char *c = malloc(sizeof(*c) * (n + 1));.
since fgets() will store the newline, you should increase the allocation size by 1 to avoid leaving the newline in the input stream, but you will need to avoid including the newline in the characters to reverse. In all cases, you must pass the size of the array to fgets(), not n because fgets() would then only store n - 1 bytes into the array and set c[n - 1] to a null terminator, which causes the reversed string to start with a null terminator, making it an empty string.
you do not test if fgets() succeeded at reading standard input.
you do not compute the number of characters to reverse. If the user entered fewer characters than n, you will transpose bytes beyond those that were entered, possibly null bytes which will make the reversed string empty (this is a good explanation for what you observe).
the transposition loop should iterate for i = 0 while i < n, not n + 1.
you do not set the null terminator at the end of the destination array. This array is allocated with malloc(), so it is uninitialized.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argv, char *argc[]) {
if (argv != 2) {
printf("Please enter the maximum number of characters in your string!\n");
return 1;
}
int n = atoi(argc[1]);
if (n < 1) {
printf("Invalid number of characters: %d\n", n);
return 1;
}
// allocate 1 extra byte for the newline, one more for the null terminator
char *buf = malloc(n + 2);
char *out = malloc(n + 2);
printf("Enter your string: ");
if (!fgets(buf, n + 2, stdin)) {
printf("no input\n");
return 1;
}
// get the number of characters in the input before the newline, if any
int len;
for (len = 0; buf[len] && buf[len != '\n'; n++)
continue;
// if you can use the library function `strcspn()`, replace the for loop with this:
//len = strcspn(buf, "\n");
// copy the string in reverse order
for (int i = 0; i < len; i++) {
out[i] = buf[len - 1 - i];
}
// set the null terminator
out[len] = '\0';
printf("%s\n", out);
free(buf);
free(out);
return 0;
}
It is also possible that you run your program from the IDE on a system that closes the terminal window as soon as the program terminates. This would prevent you from seeing the output. Add a getchar(); before the return 0; to fix this problem or run the program manually from a shell window.
what's wrong with my code!
Key functional problems include:
To read "12345\n" with fgets() takes at least 6 bytes, 7 better1.
Missing null character on o[]
With fgets(c, n, stdin), c[n-1] is a null character and with "reversing", as code assumes n characters, c[n-1] becomes o[0] and so code prints the empty string.
// fgets(c, n, stdin); // too small
fgets(c, n + 1, stdin);
// add before printing.
o[n] = '\0';
Other minor issues exist.
1 Increase allocation too and then lop off \n from input.
your program will fail if the value n does not match the number of
characters in the input string mainly because you do not initialize
the memory that you allocate.
e.g.
n = 10
c = "hello"
length of c is 5 but you have allocated 11 bytes, so the bytes after hello\n\0 are uninitialized in c since fgets will not fill those out for you.
in memory it looks something like this
+---+---+---+---+---+---+---+---+---+---+---+
c ->| h | e | l | l | o |\n |\0 | | | | |
+---+---+---+---+---+---+---+---+---+---+---+
when you turn the string around with
*(o + i) = *(c + n - 1 - i)
since you are using n as offset to start copying characters, you start beyond "hello\n\0" copying
position 9 (10 - 1 - 0) and placing this as first character in o,
but since all of c is not initialized anything can be there, also even a \0 which could explain why you
don't print anything.
better is to once you read the string calculate the length of the string with a simple for loop
int len = 0;
for (len = 0; c[len] && c[len] != '\n'; ++len);
and then use len as the offset instead of n
*(o + i) = *(c + len - 1 + i)
Could you help please ?
When I execute this code I receive that:
AAAAABBBBBCCCCCBBBBBCOMP¬ıd┐╔ LENGTH 31
There are some weirds characters after letters, while I've allocate just 21 bytes.
#include <stdio.h>
#include <stdlib.h>
char * lineDown(){
unsigned short state[4] = {0,1,2,1};
char decorationUp[3][5] = {
{"AAAAA"},{"BBBBB"},{"CCCCC"}
};
char * deco = malloc(21);
int k;
int p = 0;
for(int j = 0; j < 4; j++){
k = state[j];
for(int i = 0; i < 5; i++){
*(deco+p) = decorationUp[k][i];
p++;
}
}
return deco;
}
int main(void){
char * lineDOWN = lineDown();
int k = 0;
char c;
do{
c = *(lineDOWN+k);
printf("%c",*(lineDOWN+k));
k++;
}while(c != '\0');
printf("LENGTH %d\n\n",k);
}
The function does not build a string because the result array does not contain the terminating zero though a space for it was reserved when the array was allocated.
char * deco = malloc(21);
So you need to append the array with the terminating zero before exiting the function
//...
*(deco + p ) = '\0';
return deco;
}
Otherwise this do-while loop
do{
c = *(lineDOWN+k);
printf("%c",*(lineDOWN+k));
k++;
}while(c != '\0')
will have undefined behavior.
But even if you will append the array with the terminating zero the loop will count the length of the stored string incorrectly because it will increase the variable k even when the current character is the terminating zero.
Instead you should use a while loop. In this case the declaration of the variable c will be redundant. The loop can look like
while ( *( lineDOWN + k ) )
{
printf("%c",*(lineDOWN+k));
k++;
}
In this case this call
printf("\nLENGTH %d\n\n",k);
^^
will output the correct length of the string equal to 20.
And you should free the allocated memory before exiting the program
free( lineDOWN );
As some other wrote here in their answers that the array decorationUp must be declared like
char decorationUp[3][6] = {
{"AAAAA"},{"BBBBB"},{"CCCCC"}
};
then it is not necessary if you are not going to use elements of the array as strings and you are not using them as strings in your program.
Take into account that your program is full of magic numbers. Such a program is usually error-prone. Instead you should use named constants.
In
char decorationUp[3][5] = {
{"AAAAA"},{"BBBBB"},{"CCCCC"}
};
your string needs 6 characters to also place the null char, even in that case you do not use them as 'standard' string but only array of char. To get into the habit always reverse the place for the ending null character
you can do
char decorationUp[3][6] = {
{"AAAAA"},{"BBBBB"},{"CCCCC"}
};
Note it is useless to give the first size, the compiler counts for you
Because in main you stop when you read the null character you also need to place it in deco at the end, so you need to allocate 21 for it. As before you missed the place for the null character, but here that produces an undefined behavior because you read after the allocated block.
To do *(deco+p) is not readable, do deco[p]
So for instance :
char * lineDown(){
unsigned short state[] = {0,1,2,1};
char decorationUp[][6] = {
{"AAAAA"},{"BBBBB"},{"CCCCC"}
};
char * deco = malloc(4*5 + 1); /* a formula to explain why 21 is better than 21 directly */
int k;
int p = 0;
for(int j = 0; j < 4; j++){
k = state[j];
for(int i = 0; i < 5; i++){
deco[p] = decorationUp[k][i];
p++;
}
}
deco[p] = 0;
return deco;
}
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);
As marked in the code, the first printf() rightfully prints only the i-th line of the matrix. But outiside the loop, both printf() and strcat() act on the whole matrix from i-th line on as a single-lined string. This means that
printf("%s\n",m_cfr[0])
will print whole matrix, but m_cfr[i] will print whole matrix from the i-th line on. char* string is a single lined string with no spaces.
trasp(char* string)
{
int row = strlen(string) / 5;
char m[row][5];
char m_cfr[row][5];
char cfr[row*5];
memset(cfr, 0, row * 5);
int key[5] = {3, 1, 2, 0, 4};
int k = 0;
for (i = 0 ; i < row ; i++)
{
strncpy(m[i], string + k, 5);
m[i][5] = '\0';
k += 5;
}
for (i = 0 ; i < row ; i++)
{
for (j = 0 ; j < 5 ; j++)
{
m_cfr[i][key[j]] = m[i][j];
}
m_cfr[i][5] = '\0';
printf("%s\n", m_cfr[i]); //--->prints only line i
}
printf("%s\n", m_cfr[0]); //prints whole matrix
strcat(cfr, m_cfr[0]); //concatenates whole matrix
printf("%s\n", cfr);
}
In your code, your array definition is
char m_cfr[row][5];
while you're accessing
m_cfr[i][5] = '\0';
/* ^
|
there is no 6th element
*/
You're facing off-by-one error. Out-of-bound memory access causes undefined behaviour.
Maybe you want to change the null-terminating statement to
m_cfr[i][4] = '\0'; //last one is null
%s expects a char* and prints everything until it encounters a \0. So,
printf("%s\n", m_cfr[i]);
printf("%s\n",m_cfr[0]);
strcat(cfr,m_cfr[0]);
All exhibit Undefined Behavior as m_cfr[i],m_cfr[0] and m_cfr[0] are chars and not char*s and %s as well as both the arguments of strcat expects a char*. Also, as SouravGhosh points out, using
m_cfr[i][5] = '\0';
And
m[i][5] = '\0';
Are wrong.
To fix the former issue, use
printf("%s\n", &m_cfr[i]);
printf("%s\n",m_cfr);
strcat(cfr,&m_cfr[0]);
To print the whole string and concatenate the two strings in the arguments of strcat or if you wanted to print just the chars, use
printf("%c\n", m_cfr[i]);
printf("%c\n",m_cfr[0]);
As for the latter issue, use
char m[row][5]={{0}};
char m_cfr[row][5]={{0}};