Not getting output from string array function in c - c

I was making a split function in C to use its return value in some programs. But when I checked its value using printf, I discovered that there are some errors but I was unable to fix them myself. I fixed most of the errors I could.
The code I wrote is:
#include <stdio.h>
#include <string.h>
char **split(char *token, char *delimiter, int *a[], int *size_of_a) {
int i = 0;
char **final_result;
char *str = strtok(token, delimiter);
while (str != NULL) {
*a[i] = strlen(str); //maybe one of the errors but I don't know how to fix it
//even after removing a[i] by backslash and changing it in loop and main, there is still no output received in main
getch();
for (int j = 0; j < *a[i]; j++) {
final_result[i][j] = str[j];
}
str = strtok(NULL, delimiter);
i++;
}
*size_of_a = i;
return final_result;
}
int main() {
char *parameter_1;
char *parameter_2;
int *size_1;
int size_2;
printf("Enter the token: ");
scanf("%s", &parameter_1);
printf("\nEnter the delimiter: ");
scanf("%s", &parameter_2);
char **result_2 = split(parameter_1, parameter_2, &size_1, &size_2);
printf("\nThe result is:");
for (int x = 0; x < size_2; x++) {
printf('\n');
for (int y = 0; y < size_1[x]; y++) {
printf("%c", result_2[x][y]);
}
}
getch();
return 0;
}
How can I fix the output error?

There are multiple problems in the code:
You do not allocate space for the array of pointers: final_result is uninitialized, storing anything via dereferencing it has undefined behavior, most likely a segmentation fault.
You should use strcpn() and strspn() to compute the number of tokens, allocate the array with or without an extra slot for a NULL terminator and perform a second phase splitting the tokens and storing the pointers to the array. You might want to store copies of the tokens to avoid modifying the original string that may be constant or go out of scope.
printf('\n'); is invalid: you must pass a string, not a character constant.
scanf("%s", &parameter_1); also has undefined behavior: you pass the address of a pointer instead of a pointer to an array of char.
Here is a modified version:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
// define POSIX function strndup if not available
char *strndup(const char *s, size_t n) {
size_t len;
for (len = 0; len < n && s[len]; len++)
continue;
char *ptr = malloc(len + 1);
if (ptr) {
memcpy(ptr, s, len);
ptr[len] = '\0';
}
return ptr;
}
#endif
char **split(const char *str, const char *delimiters, int **a, int *size_of_a) {
int i, count, len;
char **final_result;
const char *p;
// phase 1: count the number of tokens
p = str + strspn(str, delimiters);
for (count = 0; *p; count++) {
p += strcspn(p, delimiters);
p += strspn(p, delimiters);
}
// phase 2: allocate the arrays
final_result = calloc(sizeof(*final_result), count + 1);
if (a) {
*a = calloc(sizeof(**a), count);
}
if (size_of_a) {
*size_of_a = count;
}
// phase 3: copy the tokens
p = str;
for (i = 0; i < count; i++) {
p += strspn(p, delimiters); // skip the delimiters
len = strcspn(p, delimiters); // count the token length
if (a) {
(*a)[i] = len;
}
final_result[i] = strndup(p, len); // duplicate the token
p += len;
}
final_result[count] = 0;
return final_result;
}
// read and discard the rest of the user input line
int flush_input(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
int main() {
char buf[256];
char delimiters[20];
printf("Enter the string: ");
if (scanf("%255[^\n]", buf) != 1)
return 1;
flush_input();
printf("\nEnter the delimiters: ");
if (scanf("%19[^\n]", delimiters) != 1)
return 1;
flush_input();
int *sizes;
int count;
char **array = split(buf, delimiters, &sizes, &count);
printf("\nThe result is:\n");
for (int x = 0; x < count; x++) {
for (int y = 0; y < sizes[x]; y++) {
putchar(array[x][y]);
}
printf("\n");
}
getchar();
return 0;
}

Related

How can I write the concatenated string to the given string pointer in C?

I am having trouble with the very last line in my function, where I am stilly learning the basics of C. I have the signature of this function given and am tasked to write a function to concatenate two strings. The commented line outputs the correct result.
#include <stdio.h>
#include <stdlib.h>
// 1) len = dst-len + max_dst_len
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int total_len = len + max_dst_len;
char *new_str = malloc(sizeof(char) * total_len);
for (int i = 0; i < len; i++) {
new_str[i] = dst[i];
}
for (int i = len; i < total_len; i++) {
new_str[i] = src[i - len];
}
new_str[total_len] = '\0';
//printf("%s <--\n", new_str);
dst = *new_str;
return total_len;
}
int main() {
char test1[] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, 10));
printf("%s\n", test1);
}
You should not be adding max_dst_len to the length of dst. max_dst_len is the amount of memory that's already allocated in dst, you need to ensure that the concatenated string doesn't exceed this length.
So you need to subtract len from max_dst_len, and also subtract 1 to allow room for the null byte. This will tell you the maximum number of bytes you can copy from src to the end of dst.
In your main() code, you need to declare test1 to be at least 10 bytes if you pass 10 as the max_dst_len argument. When you omit the size in the array declaration, it sizes the array just big enough to hold the string you use to initialize it. It's best to use sizeof test1 as this argument, to ensure that it's correct for the string you're concatenating to.
#include <stdio.h>
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int len_to_copy = max_dst_len - len - 1;
int i;
for (i = 0; i < len_to_copy && src[i] != '\0'; i++) {
dst[len+i] = src[i];
}
dst[i] = '\0';
//printf("%s <--\n", new_str);
return i + len;
}
int main() {
char test1[6] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, sizeof test1));
printf("%s\n", test1);
}

Need to sort a string input by the most frequent characters first in C (qsort)

I managed to sort it alphabetically but I need to sort it by the most frequent characters first after that. Since I'm new to C programming Im not sure if this alphabetical sort is needed. Also I thought about using a struct but not sure how to do the whole process with it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmpfunc(const void *a, const void *b) {
return *(char*)a - *(char*)b;
}
void AlphabetOrder(char str[]) {
qsort(str, (size_t) strlen(str), (size_t) sizeof(char), cmpfunc);
printf("%s\n", str);
}
void Max_Occurring(char *str)
{
int i;
int max = 0;
int freq[256] = {0};
for(i = 0; str[i] != '\0'; i++)
{
freq[str[i]] = freq[str[i]] + 1;
}
for(i = 0; i < 256; i++)
{
if(freq[i] > freq[max])
{
max = i;
}
}
printf("Character '%c' appears %d times", max, freq[max], str);
}
int main() {
char str1[20];
printf("Enter a string: ");
scanf("%s", &str1);
AlphabetOrder(str1);
Max_Occurring(str1);
return 0;
}
I wrote you a frequency sorter using the idea that #WeatherVane mentioned:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct cfreq {
unsigned char c;
int freq;
};
int freqcmp(const void *a, const void *b) {
struct cfreq *a2 = (struct cfreq *) a;
struct cfreq *b2 = (struct cfreq *) b;
if(a2->freq < b2->freq) return -1;
if(a2->freq == b2->freq) return 0;
return 1;
}
int freqcmpdesc(const void *a, const void *b) {
return -freqcmp(a, b);
}
void FrequencyOrder(const char str[]) {
struct cfreq cfreqs[256];
for(int i = 0; i < sizeof(cfreqs) / sizeof(*cfreqs); i++) {
cfreqs[i].c = i;
cfreqs[i].freq = 0;
}
for(int i = 0; str[i]; i++) cfreqs[str[i]].freq++;
qsort(cfreqs, sizeof(cfreqs) / sizeof(*cfreqs), sizeof(*cfreqs), freqcmpdesc);
for(int i = 0; i < sizeof(cfreqs) / sizeof(*cfreqs); i++) {
if(cfreqs[i].freq) printf("%c", cfreqs[i].c);
}
printf("\n");
}
int main() {
char str1[20];
printf("Enter a string: ");
scanf("%s", &str1);
FrequencyOrder(str1);
return 0;
}
and here is a sample session (note: output is not deterministic for letters with same frequency):
Enter a string: buzz
zbu
If you want duplicate letters in the output then replace the print with a loop along these lines:
while(cfreqs[i].freq--) printf("%c", cfreqs[i].c);
Im not sure if this alphabetical sort is needed.
It is not needed, yet if done, Max_Occurring() can take advantage of a sorted string.
Since the string is sorted before calling Max_Occurring(), compute the max occurring via a count of adjacent repetitions of each char.
// Untested illustrative code.
// str points to a sorted string.
void Max_Occurring(const char *str) {
char max_ch = '\0';
size_t max_occurence = 0;
char previous = '\0';
size_t occurrence = 0;
while (*str) {
if (*str == previous) {
occurrence++;
} else {
occurrence = 1;
}
if (occurrence > max_occurence) {
max_occurence = occurrence;
max_ch = *str;
}
previous = *str;
str++;
}
printf("Character '%c' appears %zu times", max_ch, max_occurence);
}
In the case of multiple characters with the same max occurrence, this code only reports one max.
Avoid buffer overflow
Do not use scanf("%s"... without a width limit.
Tip: enable all warnings to save time and see the problem of using &str1 when str1 should be used.
char str1[20];
...
// scanf("%s", &str1);
scanf("%19s", str1);
Avoid a negative index
If still wanting to for a frequency table, watch out for the case when char is signed and code use str[i] < 0 to index an array.
Instead:
const unsigned char *ustr = (const unsigned char *) str;
size_t freq[UCHAR_MAX + 1] = {0};
for(size_t i = 0; ustr[i] != '\0'; i++) {
freq[ustr[i]]++;
}
Here's another alternative that may be simpler.
void freqOrder( char *p ) {
#define ASCIIcnt 128 // 7bit ASCII
// to count occurences of each character
int occur[ ASCIIcnt ];
memset( occur, 0, sizeof occur );
int maxCnt = 0; // remember the highest count
// do the counting
for( ; *p; p++ )
if( ++occur[ *p ] > maxCnt )
maxCnt = occur[ *p ];
// output most frequent to least frequen
for( ; maxCnt; maxCnt-- )
for( int i = 0; i < ASCIIcnt; i++ )
if( occur[i] == maxCnt )
while( occur[i]-- )
putchar( i );
putchar( '\n' );
}
int main( void ) {
freqOrder( "The quick brown fox jumps over the lazy dog" );
return 0;
}
Output
' ooooeeehhrruuTabcdfgijklmnpqstvwxyz'

split a string by a character without strtok in c

I need to write code that reads a string of characters such as jasf#fjaf#afsj to a single dimension string and then ask for a separation character (eg: #) so it will get an output in two dimensions and for every line, it will be the words between the separation character like:
jasf
fjaf
afsj
I tried:
#include <stdio.h>
#include <string.h>
void main {
int s, k, b;
printf("please enter a long string\n");
gets(longstring);
s = strlen(longstring);
printf("please choose seperationg charcter\n");
scanf("%c", &ch);
if ((ch < 'A') || ((ch > 'Z') && (ch < 'a')) || (ch > 'z')) {
for (k = 0; k < s; k++) {
for (b = 0; longstring[k] == ch; ++b) {
strcpy(mat[b], longstring);
}
}
puts(mat[b]);
}
Your code is incomplete: the function definition for main lacks its argument list, which is not optional in C, longstring is not defined, etc.
Futhermore, your method is too complicated: you do not need to test for letters if the goal is just to output one line for each part of the string between separators.
Here is a simple solution:
#include <stdio.h>
#include <string.h>
int main() {
char longstring[256];
int i, len;
char sep;
printf("please enter a long string\n");
if (fgets(longstring, sizeof longstring, stdin)) {
len = strlen(longstring);
printf("please choose a separationg character: ");
if (scanf("%c", &sep) != 1)
return 1;
for (i = 0; i < len; i++) {
if (longstring[i] == sep)
putchar('\n');
else
putchar(longstring[i]);
}
}
return 0;
}
since your code is not complete , let me add what is missing to achieve the task :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
char** str_split(char* a_str, const char a_delim)
{
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last_comma = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = (char**) malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
int main()
{
char longstring[1024];
char** tokens;
char ch;
unsigned long s;
printf("please enter a long string\n");
gets(longstring);
s = strlen(longstring);
printf("please choose seperationg charcter\n");
scanf("%c", &ch);
if ((ch<'A') || ((ch>'Z') && (ch<'a')) || (ch>'z'))
{
tokens = str_split(longstring, ch);
if (tokens)
{
int i;
for (i = 0; *(tokens + i); i++)
{
printf("%s\n", *(tokens + i));
free(*(tokens + i));
}
printf("\n");
free(tokens);
}
}
return 0;
}

c- finding how many times a character occurs in a string

#include <stdio.h>
#include <string.h>
#define SIZE 40
int main(void)
{
char buffer1[SIZE] = "computer program";
char *ptr;
int ch = 'p', j = 0, i;
for (i = 0; i<strlen(buffer1); i++)
{
ptr = strchr(buffer1[i], ch);
if (ptr != 0) j++;
printf(" %d ", j);
}
}
I want to count how many times a character occurs in a string.
In my program I chose the character 'p'.
I know Pascal, I am learning C now. In pascal is a function called Pos(x,y) which is searching for x in y. Is something familiar to this? I think what I used here is not.
The function signature of strchr is
char *strchr(const char *s, int c);
You need to pass a char* but you have passed a char. This is wrong.
You have used the strlen in loop - making it inefficient. Just calculate the length of the string once and then iterate over it.
char *t = buffer;
while(t!= NULL)
{
t = strchr(t, ch);
if( t ) {
t++;
occurences++;
}
}
And without using standard library functions you can simply loop over the char array.
size_t len = strlen(buffer);
for(size_t i = 0; i < len; i++){
if( ch == buffer[i]) occurences++;
}
Or alternatively without using strlen
char *p = buffer;
while(*p){
if( *p == ch ){
occurences++;
}
p++;
}
Or
for(char *p = buffer; *p; occurences += *p++ == ch);
Try this example :
int main()
{
char buffer1[1000] = "computer program";
char ch = 'p';
int i, frequency = 0;
for(i = 0; buffer1[i] != '\0'; ++i)
{
if(ch == buffer1[i])
++frequency;
}
printf("Frequency of %c = %d", ch, frequency);
return 0;
}

separating a string to a double array with seperators

i want to make a function that returns an array of doubles from a specific string.
i've tried multiple options and did not succeed
i have a given function createWeightsArray and i need to fill it.
the numofgrades will be also given which is helpful
the string will be something like: "30% 40% 50%" and i in need a double array {0.3,0.4,0.5}
this is my latest try:
double* createWeightsArray(char* str, int numOfGrades) {
double *gradesweight;
gradesweight = (double*)malloc(numOfGrades * sizeof(double));
int i = 0, n = 0;
while (*str != '\0') {
while (strchr("%", *str)) ++str;
if (*str == '\0') break;
*(gradesweight + n) = (atof(str) / 100);
n++;
str = strstr(str, "% ");
if (str == NULL) break;
*str = '\0';
++str;
}
return gradesweight;
any help will be apprciated
Check it out.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
double* str2double(char *string, int length)
{
int index = 0;
const char delimitor[2] = "% "; /* Delimintor, used the break the string */
char *token;
double *array = malloc(sizeof(double) * length);
if (array == NULL){
fprintf(stderr, "Failed to allocate memory \n");
return NULL;
}
/* get the first token */
token = strtok(string, delimitor);
/* walk through other tokens */
for( index=0; token != NULL && index < length ; index++)
{
array[index] = strtod(token, &token) / 100;
token = strtok(NULL, delimitor);
}
return array;
}
int main()
{
char str[] = "30% 40% 80% 60%";
double *ptr = str2double(str, 4);
if (ptr != NULL) {
for (int i = 0; i < 4; i++)
printf( "%f\n", ptr[i]);
}
return 0;
}
You can use strtoklike this
double* createWeightsArray(char* str1, int numOfGrades) {
double *gradesweight;
char *str =strdup(str1);
gradesweight = (double*)malloc(numOfGrades * sizeof(double));
int i = 0;
*gradesweight = atof(strtok(str,"%"))/100;
i++;
while (--numOfGrades) {
*(gradesweight+i) = atof(strtok(NULL,"%") )/100;
i++;
}
return gradesweight;
}
As you are certain that numOfGrades are provided so better check for zero value of numberOfGrades before calling this function.

Resources