So i'm trying to create a simple String struct which will contain the text of the string and the size of it, at least for now. However I'm having issues allocating my struct. Right now i'm simply trying to get a size of 1 character to work, but its simply crashing at this point and i don't know what i'm doing wrong with the allocation, please help.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
char* text;
int size;
}String;
String* getString();
int main(int argc, char** argv){
String* str1 = getString();
printf("%s",str1->text);
free(str1);
return 0;
}
String* getString(){
String* str = (String*)malloc(sizeof(String));
scanf("%s",str->text);
str->size++;
return str;
}
You need to allocate memory for the structure but also for text string.
scanf("%s",str->text);
str->text is an uninitialized pointer.
You don't allocate any memory for str->text. You leave it uninitialized, so your program invokes undefined behavior.
You need to allocate memory for it using str->text = malloc(MAX_SIZE); where MAX_SIZE is the maximal size for the string. Alternatively, if your strings will be short, you may use a regular, fixed-szie array instead.
Furthermore, you probably do not want to use scanf() for scanning strings. One particular reason is that %s makes scanf() stop at the first whitespace character. Another reason is that it's not trivial to prevent scanf() from writing past the buffer if it's too small.. How about using fgets() instead?
fgets(str->text, MAX_SIZE, stdin);
is a better and safer approach.
int main(int argc, char** argv){
String* str1 = getString();
printf("%s",str1->text);
free(str1->text);
free(str1);
return 0;
}
String* getString(){
String* str = (String*)malloc(sizeof(String));//for struct
str->size = 16;//initialize
str->text = (char*)malloc(sizeof(char)*str->size);//for input text
int ch, len;
while(EOF!=(ch=fgetc(stdin)) && ch != '\n'){
str->text[len++]=ch;
if(str->size==len){
str->text = realloc(str->text, sizeof(char)*(len+=16));
}
}
str->text[len++]='\0';
str->text = realloc(str->text, sizeof(char)*(str->size=len));
return str;
}
Related
How can I implement a function that will concatenate something to a char* (not char array)?
Example of what I want:
#include <stdio.h>
#include <string.h>
int main() {
char* current_line;
char temp[1];
sprintf(temp, "%c", 'A');
// This causes a seg fault. I of course don't want that, so how do I get this to work properly?
strcat(current_line, temp);
return 0;
}
How can I fix this to work properly (and please, tell me if I need to add anything to my question or point me in the right direction because I couldn't find anything)?
Edit: I made this but it seg faults
char* charpointercat(char* mystr, char* toconcat) {
char ret[strlen(mystr) + 1];
for(int i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
return ret;
}
You have 3 problems:
You do not allocate memory for current_line at all!
You do not allocate enough memory for temp.
You return a pointer to a local variable from charpointercat.
The first one should be obvious, and was explained in comments:
char *current_line only holds a pointer to some bytes, but you need to allocate actual bytes if you want to store something with a function like stracat.
For the secoond one, note that sprintf(temp, "%c", 'A'); needs at least char temp[2] as it will use one byte for the "A", and one byte for terminating null character.
Since sprintf does not know how big temp is, it writes beyond it and that is how you get the segfault.
As for your charpointercat once the function exits, ret no longer exists.
To be more precise:
An array in C is represented by a pointer (a memory address) of its first item (cell).
So, the line return ret; does not return a copy of all the bytes in ret but only a pointer to the first byte.
But that memory address is only valid inside charpointercat function.
Once you try to use it outside, it is "undefined behavior", so anything can happen, including segfault.
There are two ways to fix this:
Learn how to use malloc and allocate memory on the heap.
Pass in a third array to the function so it can store the result there (same way you do with sprintf).
From the first code you posted it seems like you want to concatenate a char to the end of a string... This code will return a new string that consists of the first one followed by the second, it wont change the parameter.
char* charpointercat(char* mystr, char toconcat) {
char *ret = (char*) malloc(sizeof(char)*(strlen(mystr) + 2));
int i;
for(i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
ret[i] = toconcat;
ret[i + 1] = '\0';
return ret;
}
This should work:
char* charpointercat(char* mystr, char* toconcat) {
size_t l1,l2;
//Get lengths of strings
l1=strlen(mystr);
l2=strlen(toconcat);
//Allocate enough memory for both
char * ret=malloc(l1+l2+1);
strcpy(ret,mystr);
strcat(ret,toconcat);
//Add null terminator
ret[l1+l2]='\0';
return ret;
}
int main(){
char * p=charpointercat("Hello","World");
printf("%s",p);
//Free the memory
free(p);
}
I've been trying to code a really simple string to morse code converter in C for a few hours now and I finally got it to compile without any warnings. I'm a beginner in C so I really cannot understand how to fix my code. I believe the problem should be in how I pass strings around with pointers and etc, since this is the part I do not understand the most. I found an example on how to do it, but I still couldn't understand it, and there wasn't any specific case that would be similar to mine, since I want it to read strings from the arguments (all arguments are strings/words).
And now I'm getting a segmentation fault when trying to run it:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int to_morse(char *);
int main(int argc, char **argv)
{
char morse[80];
char *temp;
for (int counter = 1; counter < argc; counter++)
{
*temp = to_morse(argv[counter]);
strcat(temp, morse);
printf("%s", morse);
}
return 0;
}
int to_morse(char *str)
{
char *morse[27] = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
char *output;
char character;
for (int counter = 0; str[counter] != '\0'; counter++)
{
character = toupper(str[counter]);
strcat(morse[character-'A'], output);
}
return *output;
}
I believe this is not a correct way to pass around strings using pointers, but I cannot figure out the right way. How would I be able to make my code work?
Note: I'm aware this might have a duplicate somewhere.. however, there are tons of segmentation fault questions and all of them are really specific and do not cover my scenario, so I couldn't find one.
There is so much going wrong with your code.
Firstly, strcat takes 2 parameters - a destination and then a source. In all cases that you're using it, you've got them the wrong way around.
Secondly, your function to_morse returns an int when you want it to return a char *. That would be how you pass around pointers.
Thirdly, you don't allocate any memory for output in that function, so even if you had the strcat the right way around, you've not got anywhere to store the morse code. That'll also be where the code is crashing as you're passing in an uninitialised pointer to strcat.
Finally, you should probably check that the character you're trying to convert to morse is a letter, otherwise you'll go out of bounds on your array.
Here is how your code should look. I've also tweaked it so that you put a space between each morse "letter" as otherwise you'd not be able to tell where one begins and another ends.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
char *to_morse(char *);
int main(int argc, char **argv)
{
char *temp;
for (int counter = 1; counter < argc; counter++)
{
temp = to_morse(argv[counter]);
printf("%s", temp);
free(temp); // Always remember to free memory you allocate
}
return 0;
}
char *to_morse(char *str)
{
char *morse[27] = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
char *output=malloc((strlen(str)*5)+1); // Always remember to allocate 1 more char than you need to store the NUL terminate when allocating memory for strings.
output[0] = '\0'; // strcat need a null terminator in the string.
char character;
for (int counter = 0; str[counter] != '\0'; counter++)
{
if(isalpha(str[counter]))
{
character = toupper(str[counter]);
strcat(output,morse[character-'A']);
strcat(output," ");
}
}
return output;
}
I have been looking on internet for this and so far i just found a lot of questions for specific answer and not a general one.
i am kind of rusty on C. And i want to make a function that will return an array of char.
this is what i got and is not working. basically a way to convert a byte array to an array of chars to do atoi later..
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *get_char(int my_byte[], int packetsize)
{
char *array_char=(char *) malloc(sizeof(char)*10); //trying this but didnt work
// char array_char[10]; //i had it like this before(was told to do it)
for(int i=0;i<10;i++)
{
array_char[i]=my_byte[i]+0;
}
return array_char;
}
int main()
{
int byte_array[]={1,2,3,4,5,6,7,8,9,0};
char *temp;
char data;
temp=get_char(byte_array,10);
data=*temp;
printf("String point %s ",data);
}
Two fixes:
As you want to convert to char, then
array_char[i]=my_byte[i]+0; should be array_char[i]=my_byte[i]+'0'; Note '0' is character (that will be converted to int) instead of numeric 0 (which doesn't do anything).
Also you must free temp pointer in main as that memory is dynamically allocated in get_char() function.
Edit: just notice another issue in your get_char()
char *array_char=(char *) malloc(sizeof(char)*10);
should be
char *array_char= malloc(sizeof(char)*(packetsize+1));
After the for loop, ensure the buffer is NUL-terminated:
array_char[packetsize] = '\0';
Notice that your packetsize is never used - you should get some compiler warning about it. It's bad to hard code 10 in your malloc - it's actually the whole idea of parsing the packetsize as a parameter - so use it properly.
You need to watch out for these things:
You need to add a null-terminating character at the end of *array_char, otherwise using this pointer allocated from the heap will cause undefined behaviour.
You can simply allocate *array_char like this:
char *array_char = malloc(packetsize+1);
As sizeof(char) is 1, and +1 for trailing nullbyte.
You also don't need to cast return of malloc().
Instead of passing 10 as packetsize to get_char(), you should pass this size as sizeof(arr) / sizeof(arr[0], which is the calculated size of the array. This can be a size_t variable declared somewhere or even a macro.
malloc() needs to be checked, as it can return NULL if unsuccessful.
You need to free() temp at some point in the program.
array_char[i]=my_byte[i]+0; needs to be array_char[i]=my_byte[i]+'0'; instead, as '0' is the ascii code for a zero character.
char data needs to be char *data, as temp is a pointer.
If you compile with -Wall -Wextra, you will see that this line:
data=*temp;
Is dangerous, and will trigger warnings of making pointers from integers without a cast. It will most likely lead to a segmentation fault. If temp and data are both pointers, then you can simply use:
data=temp;
Which sets data to the address of temp. Sometimes this is written as data = &(*temp);, but this is harder to read. Although their is no need for data, and using temp alone should be fine.
Your code can then look like this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
char *get_char(int my_byte[], size_t packetsize) {
char *array_char = malloc(packetsize+1);
const char ascii = '0';
size_t i;
if (!array_char) {
printf("Cannot allocate %zu bytes\n", packetsize+1);
exit(EXIT_FAILURE);
}
for(i = 0; i < packetsize; i++) {
array_char[i] = my_byte[i] + ascii;
}
array_char[i] = '\0'; /* or array_char[packetsize] = '\0' */
return array_char;
}
int main(void) {
int byte_array[]={1,2,3,4,5,6,7,8,9,0};
char *temp, *data;
temp = get_char(byte_array, ARRAYSIZE(byte_array));
data = temp;
printf("String point %s\n", data);
printf("String converted into number = %d\n", atoi(data));
free(temp);
temp = NULL;
return 0;
}
You can also look into strtol, which is better than using atoi() in terms of error checking.
It is Not Wise Idea to Return a Array From A Function. So how to return a string then? As most of libc functions use we can use some thing like that (i.e) passing a buffer along with our input and expect function to use output buffer to give us result.
Some issue to take care while coding
write your logic first.
try to use available functions from libc.
while dealing with byte data/binary data be take precaution of buffer overflow.
don't allocate in a function and de-allocate in another function.
Below is Example of your code with modification.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <stdint.h>
int get_char(uint8_t my_byte[], int packetsize, char *buffer, int max_buffer)
{
int byte_itr, buf_itr;
char temp_buf[16]={0x00};
for(byte_itr=0, buf_itr=0; byte_itr<packetsize && max_buffer > buf_itr; byte_itr++)
{
memset(temp_buf, 0x00, sizeof(temp_buf));
char temp_ch = my_byte[byte_itr];
snprintf(temp_buf, sizeof(temp_buf), "%d", temp_ch);
if( buf_itr+strlen(temp_buf) >=max_buffer){
break;
}else{
buf_itr += strlen(temp_buf);
strcat(buffer, temp_buf);
if(byte_itr+1 < packetsize){
strcat(buffer, ",");
buf_itr += 1;
}
}
}
return buf_itr;
}
int main()
{
uint8_t byte_array[]={1,2,3,4,5,6,7,8,9,0};
char char_array[32]={0x00};
int len = get_char(byte_array, 10, char_array, sizeof(char_array));
printf("String point %s : len %d\n", char_array, len);
}
NOTE:
when length return and size of output buffer same then buffer full condition happened.
I am fairly new to C programming and still trying to understand all the nooks and crannies of C. I am writing a program to concatenate two strings. But I am getting an error which I don't understand. Here is the output.
Asfakul
The Length of the String name is 7
The Length of the String fullname is 7
L
Segmentation fault (core dumped)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char const *argv[])
{
char *name="Asfakul";
char *surname="Laskar";
char *fullname;
int i=0;
//Allocate Memory of 100 char
fullname=(char*)malloc(100*sizeof(char));
fullname=name;
while(*name !='\0')
{
i++;
name++;
}
// Allocate Memory for FullName
//fullname=(char*)malloc(100*sizeof(char));
//Coppied the spurce String
// fullname=name; // Here this assignement will not work as Pointer name now point to NULL character of String Name.
puts(fullname);
printf("The Length of the String name is %d\n",i );
printf("The Length of the String fullname is %d\n",strlen(fullname) );
while(*surname !='\0')
{
printf("%c\n",*(fullname+i+1));
*(fullname+i+2)=*(surname);
printf("%c\n",*(surname));
i++;
surname++;
}
puts(fullname);
return 0;
}
Please help me understand what I am doing wrong.
fullname = name; assigns the pointer name to fullname. You subsequently modify the data at name. That's not allowed since name points to a read-only string literal.
You're also discarding the malloc pointer, leaving you no way to free the allocated memory! This will not end well.
You should take a deep copy of name instead: consider using a strncpy.
If you were to use const char* for the string literals then compilation should fail, so protecting yourself from these kind of things.
*(fullname+i+2)=*(surname);
Here you are trying to cat the surname at the end of the name:
char *name="Asfakul";
This is read-only space.
You should alloc enough space for both strings and copy them inside the allocated space.
You can past char by char
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char const *argv[])
{
char *name="Asfakul";
char *surname="Laskar";
char *fullname;
int i=0;
//Allocate Memory of 100 char
fullname=malloc(100*sizeof(char));
while(*name !='\0')
{
fullname[i++] = *name++;
}
fullname[i] = '\0';
puts(fullname);
printf("The Length of the String name is %d\n",i );
printf("The Length of the String fullname is %zd\n",strlen(fullname) );
fullname[i++] = ' ';
while(*surname !='\0')
{
fullname[i++]= *surname++;
}
fullname[i] = '\0';
puts(fullname);
free(fullname);
return 0;
}
I have the following code that prints as intended in ubuntu linux but prints nothing in cygwin in windows. However, if I get rid of free(t) in is_rotation function then it works ok. I want to know if I am doing bad memory management or it is a cygwin issue. Why it is happening. And any other suggestion to improve the memory management.
Here is the code:
/**
* sub is a substring of str or not
**/
int is_substring(const char* str,const char* sub){
const char* s1=str;
const char* s2=sub;
int count=0;
while(1){
if(*s2=='\0') return 1;
else if(*s1=='\0') return 0;
else if(*s1==*s2){
count++;
s2++;
}
else{
if(count!=0){
s1-=count;
count=0;
s2=sub;
}
}
s1++;
}
return 0;
}
/**
* s1 and s2 are rotations of eachother or not, given only the is_substring function.
**/
int is_rotation(const char* s1,const char* s2){
int l1=strlen(s1);
if(l1!=strlen(s2)) return 0;
char* t=malloc(2*l1*sizeof(char));
strcat(t,s1);
strcat(t,s1);
int r=is_substring(t,s2);
free(t);
return r;
}
/**
* USAGE: ./a.out string1 string2
**/
int main(int argc, char *argv[]){
if(argc<3) return 1;
printf("is_substring=%d",is_substring(argv[1],argv[2]));
printf("\nis_rotation=%d",is_rotation(argv[1],argv[2]));
return 0;
}
Thanks for the help :)
The issue is in the first strcat() call. You should replace it with a strcpy() instead.
int is_rotation(const char* s1,const char* s2){
int l1=strlen(s1);
if(l1!=strlen(s2)) return 0;
char* t=malloc(2*l1*sizeof(char) + 1);
strcpy(t,s1); // initialize with strcpy() so we have a null in the string
strcat(t,s1);
int r=is_substring(t,s2);
free(t);
return r;
}
Note that malloc() does not initialize the buffer it allocates normally. Perhaps the one on ubuntu does, but it is not guaranteed. In cygwin, the buffer is not initialized, so the strcat() is walking memory looking for a null before it copies the string... which very likely is past the end of your allocated buffer.
Also, you have to add an extra character to the buffer to hold the null terminator for the final string... it's 2x the length of l1 + 1 for the null terminator
Here is a bug that kills your stack:
char* t=malloc(2*l1*sizeof(char));
strcat(t,s1);
strcat(t,s1);
The first strcat adds characters to somewhere... As you are using malloc the contents of the t buffer is unknown. Also you need one more byte for zero.
char* t=malloc(2*l1+1); // (2*l1+1)*sizeof(char)
strcpy(t,s1);
strcat(t,s1);