convert morse code to english in c - c

I have already done some code but it does not run correctly
what I have done so far
void keyread1(void)
{
char *string1= (char*) malloc (20);//char pointer pointing to allocated memory
char *string2= (char*) malloc (20);
char *string3= (char*) malloc (20);
char *string4= (char*) malloc (20);
string4[0]='\0';
printf("Enter word to convert to morse code: \n");
scanf("%s", string1);
while (string1!='\0')
{
int z=0,a=0;
strncpy(string2+a, string1+z,4 );
string3=morse2english(string2);
strncat(string4+a,string3,1);
z=z+4;
}
printf("morse code string: %s\n",string4);
free(string1);
return;
}
char *morse2english(char *morsecode)
{
int j=0;
int a=0;
char *azarray=(char*)malloc(26);
strcpy(azarray, "abcdefghijklmnopqrstuvwxyz");
char *morsearray=(char*)malloc(104*sizeof(char));
strcpy(morsearray, ".- -...-.-.-.. . ..-.--. ...... .----.- .-..-- -. --- .--.--.-.-. ... - ..- ...-.-- -..--.----..");
for (int i = 0; i < 104; ++i )
for(int j=0;j<4;j++)
if((morsecode[j++] == morsearray[i++]))
a =((morsearray[i-4])/4);
char *ch =(char*)malloc(1*sizeof(char));
ch=azarray+a;
return ch;
}
the function keyread is supposed to split the morse string into 4 chars
and pass that to the morse2english function which is supposed to find the alphabetical representation of the morse code
and return it to the keyread function and add it to string4

I was putting the problems in a comment, but there are just too many! You really need to go back and study some more - especially about dynamic memory allocation!
in keyread1:
All the strcpy stuff with malloced buffers is not necessary. eg: you malloc 20 bytes for string3 but before you use it you say string3=..., so it's an instant leak!
while(string1 != '\0') is not comparing apples to apples: string 1 is a pointer, \0 is a character. You probable mean *string1, but then you never modify string1, so the loop wont end.
You never modify a in the loop, so you aren't appending to the string4
The result of morse2english is dynamically allocated but you never free it.
in morse2english:
you malloc an array of 26, (which doesn't allow a null terminator so you have a buffer overrun)
you never free azarray - why malloc in the first place, you don't modify it, so a string literal would work.
Ditto for morsearray (I didn't count it, but you don't change it, so no need to malloc and strcpy)
The for loop appears to be gibberish: for each individual char in all the morse code, look at the input (and modify the indexes used by the for loops)

Related

Dereference C string pointer into variable

I have the following simple program which creates a pointer to the first character of a string:
char str[] = "Hello world";
char *p = &str[0];
How can I then get this string back into a variable using only the pointer?
Dereferencing the pointer just gives the first character of the string - as somewhat expected - so I'm assuming that there is no 'simple' way to achieve this and it will instead require writing extra code.
The current way I would approach this would be as follows:
Iterate from the pointer until a null terminator is reached to find the length of the string
Create a new char array with this length
Iterate through again inserting characters into this array
Is there a library function to achieve this, or if not, a simpler way that doesn't involve iterating twice?
Yes you have to "do it by hand". Because there are no objects in C - you need to take care of all that happens in the code.
You can use malloc, strlen and memcpy:
char str[] = "Hello world";
char *p = malloc(strlen(str) + 1);
if (!p) { abort(); }
memcpy(p, str, strlen(str) + 1);
You can use strcpy and forget about one strlen:
char *p = malloc(strlen(str) + 1);
if (!p) { abort(); }
strcpy(p, str);
Or you can use strdup from POSIX or a C extension:
char *p = strdup(str);
if (!p) { abort(); }
...
Is there a library function to achieve this, or if not, a simpler way that doesn't involve iterating twice?
As said in comment, strdup() will do exactly what you want. But here there is another problem (by your point of view): strcpy() will iterate the string twice, because there is no other way to duplicate a string.
By definition, strings in C are a sequence of characters somewhere in memory, with the last one character being a NUL (with single L), the value 0 (in a char). References to strings are pointers to the first character in the sequence depicted above. Note that two different strings can point to the same memory (they are not so different then...), or a string can point into the middle of another. These two cases are somewhat particular but not uncommon. The memory for strings must be managed by the programmer, who is the only one to know where allocate and deallocate space for strings; functions like strcpy() do nothing special in this regard, they are (presumably) well written and optimized, so maybe to copy a string the behavior is not plain as I depicted it before, but the idea is the same.
try this code:
#include "stdio.h"
int main(){
char str[] = "Hello world";
int count = 12;
char (*p)[12] = &str;
printf("%c\n",(*p)[0]);
printf("%c\n",(*p)[1]);
printf("%c\n",(*p)[2]);
printf("%c\n",(*p)[3]);
printf("%s\n",(*p));
}
Here's how I would make a copy of a string using only the standard library functions:
#include <stdio.h> // printf
#include <stdlib.h> // malloc
#include <string.h> // strcpy
int main(void)
{
char str[] = "Hello world"; // your original string
char *p = (char *)malloc(strlen(str) + 1); // allocate enough space to hold the copy in p
if (!p) { // malloc returns a NULL pointer when it fails
puts("malloc failed.");
exit(-1);
}
strcpy(p, str); // now we can safely use strcpy to put a duplicate of str into p
printf("%s\n", p); // print out this duplicate to verify
return 0;
}

random chars in dynamic char array C

I need help with char array. I want to create a n-lenght array and initialize its values, but after malloc() function the array is longer then n*sizeof(char), and the content of array isnt only chars which I assign... In array is few random chars and I dont know how to solve that... I need that part of code for one project for exam in school, and I have to finish by Sunday... Please help :P
#include<stdlib.h>
#include<stdio.h>
int main(){
char *text;
int n = 10;
int i;
if((text = (char*) malloc((n)*sizeof(char))) == NULL){
fprintf(stderr, "allocation error");
}
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
int test = strlen(text);
printf("\n%d\n", test);
puts(text);
free(text);
return 0;
}
Well before using strcat make
text[0]=0;
strcat expects null terminated char array for the first argument also.
From standard 7.24.3.1
#include <string.h>
char *strcat(char * restrict s1,
const char * restrict s2);
The strcat function appends a copy of the string pointed to by s2
(including the terminating null character) to the end of the string
pointed to by s1. The initial character of s2 overwrites the null
character at the end of s1.
How do you think strcat will know where the first string ends if you don't
put a \0 in s1.
Also don't forget to allocate an extra byte for the \0 character. Otherwise you are writing past what you have allocated for. This is again undefined behavior.
And earlier you had undefined behavior.
Note:
You should check the return value of malloc to know whether the malloc invocation was successful or not.
Casting the return value of malloc is not needed. Conversion from void* to relevant pointer is done implicitly in this case.
strlen returns size_t not int. printf("%zu",strlen(text))
To start with, you're way of using malloc in
text = (char*) malloc((n)*sizeof(char)
is not ideal. You can change that to
text = malloc(n * sizeof *text); // Don't cast and using *text is straighforward and easy.
So the statement could be
if(NULL == (text = (char*) malloc((n)*sizeof(char))){
fprintf(stderr, "allocation error");
}
But the actual problem lies in
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
The strcat documentation says
dest − This is pointer to the destination array, which should contain
a C string, and should be large enough to contain the concatenated
resulting string.
Just to point out that the above method is flawed, you just need to consider that the C string "A" actually contains two characters in it, A and the terminating \0(the null character). In this case, when i is n-2, you have out of bounds access or buffer overrun1. If you wanted to fill the entire text array with A, you could have done
for(i = 0; i < n; i++){
// Note for n length, you can store n-1 chars plus terminating null
text[i]=(n-2)==i?'A':'\0'; // n-2 because, the count starts from zero
}
//Then print the null terminated string
printf("Filled string : %s\n",text); // You're all good :-)
Note: Use a tool like valgrind to find memory leaks & out of bound memory accesses.

How to create a dynamic array of strings with the space just necessary for each string in C

I want to have an array of pointers to strings,and just get the space necessary for each string.
I know malloc and getc are required but not familiar with the use of them.
Here is part of my code. It gives the error message "Segmentation fault" ....
char **allstrs;
char *one_str;
int totstrs=0,current_size= INITIALSIZE;
allstrs = (char **)malloc(current_size*sizeof(char*)); //dynamic array of strings
while(getstr(one_str)!=EOF){
if(totstrs == current_size){
current_size *=2;
allstrs = realloc(allstrs, current_size*sizeof(char*));
}
strcpy(allstrs[totstrs],one_str);
printf("String[%d] is : %s\n",totstrs,allstrs[totstrs]);
totstrs ++;
}
free(allstrs); //deallocate the segment of memory
return 0;
and the function getstr called
char c;
int totchars=0, current_size=INITIALCHARS;
str = (char*)malloc(sizeof(char));
while(c!='\n'){
c = getc(stdin);
if(c==EOF){
return EOF;
}
if(totchars == current_size){
current_size *=2;
str = (char*)realloc(str,current_size*sizeof(char));
}
str[totchars] = c; //store the newly-read character
totchars++;
}
str[totchars]='\0'; //at the end append null character to mark end of string
return 0;
}
You're not allocating any memory for the destination string here:
strcpy(allstrs[totstrs],one_str);
At this point allstrs[totstrs] is just a wild pointer.
Allocate some memory for the destination string first:
allstrs[totstrs] = malloc(strlen(one_str) + 1);
strcpy(allstrs[totstrs],one_str);
And don't forget to free all these strings later when you're done, of course (prior to free(allstrs)).
(Alternatively take #BLUEPIXY's advice and just assign the pointer you allocated in getstr instead of using strcpy - this is probably a better solution, depending on what else you might be trying to do).
Note also that you have a few bugs in your getstr function:
(1)
char c;
should be initialised, e.g.:
char c = '\0';
(or some other suitable character).
(2)
str = (char*)malloc(sizeof(char));
should be:
str = malloc(current_size);
(3) It looks like you're not allocating the addition char necessary for storing the terminating '\0'.
General note: never cast the result of malloc in C.

Can't copy characters from pointer to another pointer(both with memory allocated)

I have a program that accepts a char input using argv from the command line. I copy the input argv[1] using strcpy to a pointer called structptr(it goes to structptr->words from struct) where memory has been allocated. I then copy character by character from the memory that the pointer structptr points to another pointer called words that points to memory that has been allocated. After i've copied one character i print that element [c] to make sure that it has been copied correctly(which it has). I then finish copying all of the characters and return the result to a char pointer but for some reason it is blank/null. After each copying of the characters i checked if the previous elements were correct but they don't show up anymore([c-2], [c-1], [c]). Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct StructHolder {
char *words;
};
typedef struct StructHolder Holder;
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
int main(int argc, char **argv){
Holder *structptr=malloc(sizeof(Holder));
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
char *charptr;
charptr=(GetCharacters(structptr));
printf("%s\n", charptr);
return 0;
At first I thought this was the problem:
char *words=malloc(sizeof(char)) is allocating 1 byte (sizeof 1 char). You probably meant char *words = malloc(strlen(ptr->words)+1); - You probably want to null check the ptr and it's member just to be safe.
Then I saw the realloc. Your realloc is always 1 char short. When i = 0 you allocate 1 byte then hit the loop, increment i and put a char 1 past the end of the realloced array (at index 1)
Also your strcpy in main is has not allocated any memory in the holder.
In these two lines,
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
need to add one to the size to hold the nul-terminator. strlen(argv[1]) should be strlen(argv[1])+1.
I think the same thing is happening in the loop, and it should be larger by 1. And sizeof(char) is always 1 by definition, so:
...
words=realloc(words,i+2);
}
words=realloc(words,i+2); // one more time to make room for the '\0'
words[strlen(ptr->words)]='\0';
FYI: Your description talks about structptr but your code uses struct StructHolder and Holder.
This code is a disaster:
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
It should be:
char *GetCharacters(const Holder *ptr)
{
char *words = malloc(strlen(ptr->words) + 1);
if (words != 0)
strcpy(words, ptr->words);
return words;
}
Or even:
char *GetCharacters(const Holder *ptr)
{
return strdup(ptr->words);
}
And all of those accept that passing the structure type makes sense; there's no obvious reason why you don't just pass the const char *words instead.
Dissecting the 'disaster' (and ignoring the argument type):
char *GetCharacters(Holder *ptr){
int i=0;
OK so far, though you're not going to change the structure so it could be a const Holder *ptr argument.
char *words=malloc(sizeof(char));
Allocating one byte is expensive — more costly than calling strlen(). This is not a good start, though of itself, it is not wrong. You do not, however, check that the memory allocation succeeded. That is a mistake.
for(i;i<strlen(ptr->words);i++){
The i; first term is plain weird. You could write for (i = 0; ... (and possibly omit the initializer in the definition of i, or you could write for (int i = 0; ....
Using strlen() repeatedly in a loop like that is bad news too. You should be using:
int len = strlen(ptr->words);
for (i = 0; i < len; i++)
Next:
words[i]=ptr->words[i];
This assignment is not a problem.
words=realloc(words,sizeof(char)+i);
This realloc() assignment is a problem. If you get back a null pointer, you've lost the only reference to the previously allocated memory. You need, therefore, to save the return value separately, test it, and only assign if successful:
void *space = realloc(words, i + 2); // When i = 0, allocate 2 bytes.
if (space == 0)
break;
words = space;
This would be better/safer. It isn't completely clean; it might be better to replace break; with { free(words); return 0; } to do an early exit. But this whole business of allocating one byte at a time is not the right way to do it. You should work out how much space to allocate, then allocate it all at once.
}
words[strlen(ptr->words)]='\0';
You could avoid recalculating the length by using i instead of strlen(ptr->words). This would have the side benefit of being correct if the if (space == 0) break; was executed.
return words;
}
The rest of this function is OK.
I haven't spent time analyzing main(); it is not, however, problem-free.

parsing a string using pointer pointing to a string without using strdup and strtok functions

I am writing a code in which i want to parse a incoming string(basically this is for embeddded project, but i want to test it first in C).The string can be a GPS output , basically a NMEA string.Even though i had done parsing using strdup and strtok function but i am, stucked up when i am doing parsing simply using a string and pointer pointing to that string.
#include<stdio.h>
int main()
{int i;
char inputstring[100]; //i assumed it to be input string, in this case enter by user.
char *ptr[12];
printf("Enter the string to be printed now.: \n");
scanf("%s",inputstring);
printf("the input string being received from the user is = \n %s \n", inputstring);
for(i=0;i<12;i++) /*used this for loop to get first 12 characters from inputstring copied into ptr[i] */
{
ptr[i] = &inputstring[i];
}
printf("value of store is = %s \n",*ptr);
return 0;
}
but the ouput of this is whole inputstring rather then the first 12 characters.I dig this out further and find that *ptr when points to inputstring, its points to the inputstring[0]
and will copy whole string in it rather then just copying first 12 characters.How can we limit this ?
Need help.I have a alternate way but need help to dig out this code of mine.
This:
char *ptr[12];
is an array of 12 character pointers, but you seem to want it to be an array of 12 characters. Remove the asterisk:
char ptr[12];
and re-name it, since ptr is a lousy name:
char tmp[12];
Then make sure that you terminate it, and have room for the terminator:
char tmp[13];
strlcpy(tmp, inputstring, sizeof tmp);
char ptr[12];
instead of
char *ptr[12];
char ptr[12]: is an array of characters with size = 12 elements of chars. the size of each element in the array is = the size of char (1 byte).
char *ptr[12]: is an array of pointers with size = 12 elements of pointers. the size of each element in the array is = the size of pointer (4 bytes for 32-bit systems and 8 bytes for 64-bit systems). each pointer in the array could point to a string (char array).
you should use the following code instead
for(i=0;i<12;i++)
{
ptr[i] = inputstring[i];
}
or more simple
memcpy(ptr, inputstring, 12);
and you have to add null charachter at the end of your ptr string before you print the ptr string.
So you have to add 1 element to the size of the ptr char array
char ptr[13];
memcpy(ptr, inputstring, 12);
ptr[12] = '\0';
printf("value of store is = %s \n",ptr);

Resources