So basically what my program did before i had to change it so that it would accept arbitrary values, was to take x-amount of words and the size of the words would also be arbitrary. (both are user inputted). I did this via a multiArray.
Then sorted according to alphabetical-order.
I'm just going to put it out there as my code is shit and I'm very unfamiliar with the usage of arbitrary-strings and pointers. I've read up on it in the manual but the concept needs to sink in a little bit first i believe. Anyhow, I get the error: "Abort trap: 6" when i run the program. Could anyone please help me fix this problem so that i can see how the code would look like if it was actually working, i think that would help me understand both pointers and allocating memory a lot better. Forever in debt if you do.
Current code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LENGTH 10
int main(){ //8
char *name;
char tname[] = {0};
char temp[] = {0};
int i=0, j=0, n=0;
ssize_t bytes_read;
size_t bytes_number;
printf("Enter the amount of words you want to input: ");
scanf("%d", &n);
printf("Enter %d words: ",n);
bytes_number = MAX_LENGTH;
name = (char *) malloc (bytes_number+ 1);
bytes_number = 0;
bytes_read = getline(&name, &bytes_number, stdin);
if (bytes_read == -1){
puts("ERROR!");
free(name);
}
for (i = 0; i < n; i++){
strcpy(&tname[i], &name[i]);
}
for (i = 0; i < n - 1 ; i++){
for ( j = i + 1; j < n; j++){
if (strcmp(&name[i], &name[j]) > 0){
strcpy(temp, &name[i]);
strcpy(&name[i], &name[j]);
strcpy(&name[j], temp);
}
}
}
printf("\n------------------------------------------\n");
printf("%-3s %4s %11s\n", "Input","|", "Output");
printf("------------------------------------------\n");
for (i = 0; i < n; i++)
{
printf("%s\t\t%s\n", &tname[i], &name[i]);
}
printf("------------------------------------------\n");
}
This
strcpy(&tname[i], &name[i]);
is completely wrong, if you just want to copy all the characters, then it's just
strcpy(tname, name);
which is equivalent to
for (size_t i = 0 ; name[i] != '\0' ; ++i)
tname[i] = name[i];
using strcpy(&tname[i], &name[i]) is wrong because it will copy all the bytes from name until '\0' is found, at every loop starting at the i-th character.
But this will fail again because tname is does not have room, it's an array with just one element.
Since you want to sort the strings, you DO NOT NEED TO COPY them. Just swap the pointers. Also
char temp[] = {0};
only allocates 1 character, thus
strcpy(temp, name);
will invoke Undefined Behavior.
Try this, maybe it's what you need
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(void)
{
char **words;
char *temp;
int word_count;
int actual_count;
char *word;
size_t length;
int result;
printf("Enter the amount of words you want to input: ");
if (scanf("%d%*c", &word_count) != 1)
return -1; // Input error
printf("Enter '%d' words:\n", word_count);
words = NULL;
word = NULL;
result = -1;
actual_count = 0;
length = 0;
for (int i = 0 ; i < word_count ; ++i)
{
char **pointer;
printf("Word(%d) > ", i + 1);
if ((length = getline(&word, &length, stdin)) <= 0)
goto cleanup;
// Grow the array of words
pointer = realloc(words, (i + 1) * sizeof(*pointer));
if (pointer == NULL)
goto cleanup; // Memory Exhausted
// Now it's safe to overwrite `words'
words = pointer;
words[i] = malloc(length);
if (words[i] == NULL)
goto cleanup; // Memory Exhausted
memcpy(words[i], word, length);
words[i][length - 1] = '\0'; // Replace '\n' with '\0'
actual_count += 1;
}
printf("Input : ");
for (int i = 0 ; i < actual_count ; ++i)
printf("%s\t", words[i]);
printf("\n");
for (int i = 0; i < actual_count - 1 ; i++)
{
for (int j = i + 1 ; j < actual_count ; ++j)
{
if (strcmp(words[i], words[j]) <= 0)
continue;
temp = words[i];
words[i] = words[j];
words[j] = temp;
}
}
printf("Output: ");
for (int i = 0 ; i < actual_count ; ++i)
printf("%s\t", words[i]);
printf("\n");
result = 0;
cleanup:
free(word);
for (int i = 0; i < actual_count ; i++)
free(words[i]);
free(words);
return result;
}
Note: This would consider an empty word (made completely of white space characters), as a valid word.
Related
This code scans number then he create array with malloc, then i scan strings, i put then inside the array with another malloc, then i sort the strings and print them. I build this code with mallocs and i put array inside array,i have leaks in this code, where i need to put free() function and how i put free()? I tried many times to solve this leaks but its not working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort(char** names, int length);
void print_array(char** names, int length);
int main()
{
int num_of_friends = 0;
int i = 0;
char name[50] = { 0 };
char** names = NULL;
printf("Enter number of friends: ");
scanf("%d", &num_of_friends);
getchar();
names = malloc(sizeof(char) * num_of_friends);
for ( i = 0; i < num_of_friends; i++)
{
printf("Enter name of friend %d: ", i + 1);
fgets(name, 50, stdin);
name[strcspn(name, "\n")] = 0;
names[i] = malloc(sizeof(char) * strlen(name));
strcpy(names[i], name);
}
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
return 0;
}
void sort(char** names, int length)
{
char temp[50] = { 0 };
int i = 0;
int j_min = 0;
int j = 0;
for ( i = 0; i < length - 1; i++)
{
j_min = i;
for ( j = i+1; j < length; j++)
{
if (strcmp(names[j], names[j_min]) < 0)
{
j_min = j;
}
}
if (j_min != i)
{
strcpy(temp, names[i]);
strcpy(names[i], names[j_min]);
strcpy(names[j_min], temp);
}
}
}
void print_array(char** names, int length)
{
int i = 0;
for (i = 0; i < length; i++)
{
printf("Friend %d: %s \n", i + 1, names[i]);
}
}
For names, you are allocating sizeof (char) times the user provided number of bytes. This is needs to be sizeof (char *), giving you enough room for each pointer value.
names = malloc(sizeof (char *) * num_of_friends);
You need to allocate one additional byte for the null terminating character ('\0'). sizeof (char) is guaranteed to be 1, making that statement redundant.
names[i] = malloc(strlen(name) + 1);
Before the end of main, you need to free each element of names, and then names itself.
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
for (i = 0; i < num_of_friends; i++)
free(names[i]);
free(names);
return 0;
Your sort function may attempt to copy strings between buffers of differing size. You need to swap pointers instead.
Example:
void swap(char **a, char **b) {
char *c = *a;
*a = *b;
*b = c;
}
void sort(char **names, size_t length) {
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++)
if (strcmp(names[i], names[j]) > 0)
swap(names + i, names + j);
}
So I have an assignment where I should delete a character if it has duplicates in a string. Right now it does that but also prints out trash values at the end. Im not sure why it does that, so any help would be nice.
Also im not sure how I should print out the length of the new string.
This is my main.c file:
#include <stdio.h>
#include <string.h>
#include "functions.h"
int main() {
char string[256];
int length;
printf("Enter char array size of string(counting with backslash 0): \n");
/*
Example: The word aabc will get a size of 5.
a = 0
a = 1
b = 2
c = 3
/0 = 4
Total 5 slots to allocate */
scanf("%d", &length);
printf("Enter string you wish to remove duplicates from: \n");
for (int i = 0; i < length; i++)
{
scanf("%c", &string[i]);
}
deleteDuplicates(string, length);
//String output after removing duplicates. Prints out trash values!
for (int i = 0; i < length; i++) {
printf("%c", string[i]);
}
//Length of new string. The length is also wrong!
printf("\tLength: %d\n", length);
printf("\n\n");
getchar();
return 0;
}
The output from the printf("%c", string[i]); prints out trash values at the end of the string which is not correct.
The deleteDuplicates function looks like this in the functions.c file:
void deleteDuplicates(char string[], int length)
{
for (int i = 0; i < length; i++)
{
for (int j = i + 1; j < length;)
{
if (string[j] == string[i])
{
for (int k = j; k < length; k++)
{
string[k] = string[k + 1];
}
length--;
}
else
{
j++;
}
}
}
}
There is a more efficent and secure way to do the exercise:
#include <stdio.h>
#include <string.h>
void deleteDuplicates(char string[], int *length)
{
int p = 1; //current
int f = 0; //flag found
for (int i = 1; i < *length; i++)
{
f = 0;
for (int j = 0; j < i; j++)
{
if (string[j] == string[i])
{
f = 1;
break;
}
}
if (!f)
string[p++] = string[i];
}
string[p] = '\0';
*length = p;
}
int main() {
char aux[100] = "asdñkzzcvjhasdkljjh";
int l = strlen(aux);
deleteDuplicates(aux, &l);
printf("result: %s -> %d", aux, l);
}
You can see the results here:
http://codepad.org/wECjIonL
Or even a more refined way can be found here:
http://codepad.org/BXksElIG
Functions in C are pass by value by default, not pass by reference. So your deleteDuplicates function is not modifying the length in your main function. If you modify your function to pass by reference, your length will be modified.
Here's an example using your code.
The function call would be:
deleteDuplicates(string, &length);
The function would be:
void deleteDuplicates(char string[], int *length)
{
for (int i = 0; i < *length; i++)
{
for (int j = i + 1; j < *length;)
{
if (string[j] == string[i])
{
for (int k = j; k < *length; k++)
{
string[k] = string[k + 1];
}
*length--;
}
else
{
j++;
}
}
}
}
You can achieve an O(n) solution by hashing the characters in an array.
However, the other answers posted will help you solve your current problem in your code. I decided to show you a more efficient way to do this.
You can create a hash array like this:
int hashing[256] = {0};
Which sets all the values to be 0 in the array. Then you can check if the slot has a 0, which means that the character has not been visited. Everytime 0 is found, add the character to the string, and mark that slot as 1. This guarantees that no duplicate characters can be added, as they are only added if a 0 is found.
This is a common algorithm that is used everywhere, and it will help make your code more efficient.
Also it is better to use fgets for reading input from user, instead of scanf().
Here is some modified code I wrote a while ago which shows this idea of hashing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NUMCHAR 256
char *remove_dups(char *string);
int main(void) {
char string[NUMCHAR], temp;
char *result;
size_t len, i;
int ch;
printf("Enter char array size of string(counting with backslash 0): \n");
if (scanf("%zu", &len) != 1) {
printf("invalid length entered\n");
exit(EXIT_FAILURE);
}
ch = getchar();
while (ch != '\n' && ch != EOF);
if (len >= NUMCHAR) {
printf("Length specified is longer than buffer size of %d\n", NUMCHAR);
exit(EXIT_FAILURE);
}
printf("Enter string you wish to remove duplicates from: \n");
for (i = 0; i < len; i++) {
if (scanf("%c", &temp) != 1) {
printf("invalid character entered\n");
exit(EXIT_FAILURE);
}
if (isspace(temp)) {
break;
}
string[i] = temp;
}
string[i] = '\0';
printf("Original string: %s Length: %zu\n", string, strlen(string));
result = remove_dups(string);
printf("Duplicates removed: %s Length: %zu\n", result, strlen(result));
return 0;
}
char *remove_dups(char *str) {
int hash[NUMCHAR] = {0};
size_t count = 0, i;
char temp;
for (i = 0; str[i]; i++) {
temp = str[i];
if (hash[(unsigned char)temp] == 0) {
hash[(unsigned char)temp] = 1;
str[count++] = str[i];
}
}
str[count] = '\0';
return str;
}
Example input:
Enter char array size of string(counting with backslash 0):
20
Enter string you wish to remove duplicates from:
hellotherefriend
Output:
Original string: hellotherefriend Length: 16
Duplicates removed: helotrfind Length: 10
I have been stuck on this for a while now. I wrote my program to count word occurrence in an inputted string by the user as well to sort the words alphabetically. My issue is my program runs perfectly only if there are spaces in between the words inputted. For example, if I input "to to," my program will count those two words as two different words due to the comma rather than counting it as one word in "to" as I would like it to. It is that issue for all of my delimiters in the array const char delim[]. How can I fix this issue in my program? I really appreciate any help! My code is down below:
Edit: I took Bob's suggestion to use strchr() and it worked! My only issue is my program outputs the count for delimiters now. I was thinking of possibly writing an if statement when comparing words[i] with words[j] to see if they have the same value. Is that the best approach to it?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 1000
int main(){
char string[SIZE], words[SIZE][SIZE], temp[SIZE];
int a = 0, i = 0, j = 0, k = 0, n = 0, count;
int c = 0, cnt[26] = { 0 };
int word = 0;
int x;
printf("Enter your input string:");
fgets(string, SIZE, stdin);
string[strlen(string) - 1] = '\0';
lower(string);
/*extracting each and every string and copying to a different place */
while (string[i] != '\0'){
if (strchr(", . - !*()&^%$##<> ? []{}\\ / \"", string[i]) != NULL){
words[j][k] = '\0';
k = 0;
j++;
}else {
words[j][k++] = string[i];
}
i++;
}
words[j][k] = '\0';
n = j;
printf("Number of occurences of each word unsorted:\n");
i = 0;
/* find the frequency of each word and print the results */
while (i <= n) {
count = 1;
if (i != n) {
for (j = i + 1; j <= n; j++) {
if (strcmp(words[i], words[j]) == 0) {
count++;
for (a = j; a <= n; a++)
strcpy(words[a], words[a + 1]);
n--;
}
}//for
}
//word == strtok(string, delim);
/* count - indicates the frequecy of word[i] */
printf("%s\t%d\n", words[i], count);
i = i + 1;
}//while
printf("Alphabetical Order:\n");
/* sort the words in the given string */
for (i = 0; i < n; i++){
strcpy(temp, words[i]);
for (j = i + 1; j <= n; j++){
if (strcmp(words[i], words[j]) > 0){
strcpy(temp, words[j]);
strcpy(words[j], words[i]);
strcpy(words[i], temp);
}
} //inner for
} //outer for
i = 0;
while (i <= n) {
count = 1;
if (i != n) {
for (j = i + 1; j <= n; j++) {
if (strcmp(words[i], words[j]) == 0) {
count++;
}
}
}
printf("%s\n", words[i]);
i = i + count;
}
}
Strip every word of that delimeter before comparing. Actually you don't even need a list of delimeters because words are 'alpha' other than that it's a delimeter.
Please try this, it works, it is an extract of your own code, a little bit modified, it will give you the count, then you have to write the rest, have fun.
#include <string.h>
#define YES 1
#define NO 0
int main( )
{
char string[1000];
int i = 0;
int j = 0;
int is_this_a_word = 0;
strcpy( string, " to or not ,tobe" );
while ( string[i++] != '\0' )
{
if ( strchr( ", . - !*()&^%$##<> ? []{}\\ / \"", string[i] ) != NULL )
{
is_this_a_word = NO;
}
else
{
if ( ! is_this_a_word )
{
is_this_a_word = YES;
j++;
}
}
}
printf( "I counted %d words", j );
getchar( );
}
This is the code:
I do know what is the problem, I tried for hours to fix it, but was not successful
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void input(char ***array1,int * sizeWords,int size)
{
for (int i = 0; i < size; i++)
{
char word[81] = "";
char descrip[201] = "";
int numAgdarot = 0;
//how mach agdarot
printf("how mach of agdarrot you want? ");
scanf("%d", &numAgdarot);
//save the count of agdarot
sizeWords[i] = numAgdarot;
do
{
printf("enter word number %d: ", i);
_flushall();
gets(word);
} while (textSpace(word) == False);
(array1)[i] = (char**)malloc(numAgdarot + 1 * sizeof(char*)); //set the num and agdarot
//save the word
(array1)[i][0] = (char*)malloc(strlen(word) * sizeof(char));
strcpy(array1[i][0], word);
//save the agdarot
for (int j = 1; j <= numAgdarot; j++)
{
printf("enter descrip number %d: ", i);
_flushall();
gets(descrip);
(array1)[i][j] = (char*)malloc(strlen(descrip) * sizeof(char));
strcpy(array1[i][j], descrip);
}
}
}
int main() {
int *sizeWords = NULL;
int size = 0;
char *x=NULL;// = "jk";
char *** array1 = NULL;
printf("enter number of word: ");
scanf("%d", &size);
array1 = (char***)malloc(size * sizeof(char**));
sizeWords = (int*)malloc(size * sizeof(int));
//x = temp(x,sizeWords);
//input the word and agdarot
input(array1, sizeWords, size);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < sizeWords[i] + 1; j++)
{
free(array1[i][j]);
}
free(array1);
}
return 0;
}
I get a "HEAP CORRUPTION DELETED" error after Normal block. Why?
If i used a debugger I see the char * but i can not do a free..
Doing
malloc(strlen(word) * sizeof(char));
is almost always wrong. Remember that strings also contains an extra character that is not reported by the strlen function, the terminator character '\0'. That means your next call to strcpy will write beyond the end of the allocated memory.
What you should do is allocate memory for that extra terminator character as well:
array1[i][0] = malloc(strlen(word) + 1);
[Note that I changed the code, first because the parentheses around array are not needed, secondly because you in C one should not cast the return of malloc, and third because sizeof(char) is specified to always be 1.]
Remember to change on all other places where you use strlen in a call to malloc.
These allocations are too small:
(array1)[i][0] = (char*)malloc(strlen(word) * sizeof(char));
strcpy(array1[i][0], word);
// ...
(array1)[i][j] = (char*)malloc(strlen(descrip) * sizeof(char));
strcpy(array1[i][j], descrip);
You need an extra character for the terminating \0. strcpy() is writing into unallocated space.
Save yourself some trouble and:
(array1)[i][0] = strdup(word);
// ...
(array1)[i][j] = strdup(descrip);
And, as pointed out in the comments,
for (int i = 0; i < size; i++)
{
for (int j = 0; j < sizeWords[i] + 1; j++)
{
free(array1[i][j]);
}
free(array1);
}
should become:
for (int i = 0; i < size; i++)
{
for (int j = 0; j < sizeWords[i] + 1; j++)
{
free(array1[i][j]);
}
free(array1[i]);
}
free(array1);
This program is supposed to read in 10 strings and print the ones that end in "ed" however even though it compiles,I keep getting a segmentation fault after I enter my first string. I've tried everything and I just cant figure out why. Heres my code:
#include <stdio.h>
#include <string.h>
int main(void)
{
//Declaration of array of strings
char *strings[10];
int i = 0;
int len = 0;
//Prompts user to enter 10 strings
printf("Enter 10 strings: \n");
//Loop to read in 10 strings
for( i = 0; i < 10; i++)
{
fgets(strings[i], 100, stdin);
}
//Loop to traverse array of strings and print those ending with 'ed'
printf("The strings that end with ed are:\n");
for( i=0; i < 10; i++)
{
len=strlen(strings[i]);
len=len-1;
if(*strings[len] =='e' && *strings[len-1] =='d')
{
printf("%s", strings[i]);
}
}
return 0;
}//End of function main
You have not allocated memory for string elements. Allocate memory for it.
for(int i = 0; i < 10; i++)
strings[i] = malloc(100);
At the end do not forget to free the allocated memory using free.
for(int i = 0; i < 10; i++)
free(string[i]);
Memory is not allocated for string variable string. You only declared pointer to 10 strings
char *strings[10];
There is no memory for the string array or variable hence you have to allocate it
for(i=0;i<10;i++) {
string[i]=malloc((max_length_of_string));
}
You can take max_length_of_string to be 100.
Define the array the following way
char strings[10][100];
Also this code snippet is incorrect
for( i=0; i < 10; i++)
{
len=strlen(strings[i]);
len=len-1;
if(*strings[len] =='e' && *strings[len-1] =='d')
{
printf("%s", strings[i]);
}
}
Try the following
for( i=0; i < 10; i++)
{
len=strlen(strings[i]);
if ( len && strings[i][len - 1] == '\n' ) --len;
if ( len > 1 && strings[i][len - 1] =='d' && strings[i][len-2] =='e')
{
printf("%s", strings[i]);
}
}
Here is an example of how the program could look
#include <stdio.h>
#include <string.h>
int main( void )
{
//Declaration of array of strings
const size_t N = 10;
const size_t M = 100;
char strings[N][M];
size_t i;
size_t len;
//Prompts user to enter 10 strings
printf( "Enter %u strings: \n", N );
//Loop to read in 10 strings
for ( i = 0; i < N; i++ )
{
fgets( strings[i], M, stdin );
}
//Loop to traverse array of strings and print those ending with 'ed'
printf( "The strings that end with ed are:\n" );
for ( i = 0; i < N; i++ )
{
len = strlen( strings[i] );
if ( len && strings[i][len - 1] == '\n' ) --len;
if ( len > 1 && strings[i][len - 1] =='d' && strings[i][len - 2] =='e' )
{
printf( "%s", strings[i] );
}
}
return 0;
}
If to input
apple
room
horse
finished
close
chicken
city
done
success
opened
then the output will be
finished
opened
Some of these issues might be beyond the scope of your project.
You do not allocate any memory for your strings.
You pass an uninitialized pointer to fgets().
You do not adequately handle the problem of the input string being very long (more than 99 characters).
You do not adequately handle the problem of the input string being very short (fewer than 2 characters).
You do not adequately handle the problem of the input having fewer than the expected number or strings.
You do not adequately deal with the issue of fgets() including the newline of the input in the end of the resulting string.
You improperly use strings[len] when you mean strings[i][len].
You are checking for "de" instead of "ed" as intended.
Below is one possible solution to resolve these problems:
int
main (void)
{
char *strings[10] = {}, *x;
int i;
size_t len;
puts("Enter 10 strings:");
for (i = 0; i < 10; ++i) getline(&strings[i], &len, stdin);
puts("The strings that end with ed are:");
for (i = 0; i < 10; ++i) {
if ((x = strings[i])) {
len = strlen(x);
if (x[len-1] == '\n') x[--len] = '\0';
if (len > 1 && strcmp(x + len - 2, "ed") == 0) puts(x);
free(x);
}
}
return 0;
}