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.
Related
I am trying to add integers to a string. When I debug my code everything works perfectly fine, but when i run it normally two unwanted characters are being printed at the beginning of the string. How do I avoid this?
int number_of_ints = 5;
char s[number_of_ints*2];
char suffix[4];
for(int i = 1; i <= number_of_ints; i++){
snprintf(suffix, number_of_ints, "%d*", i);
strncat(s, suffix, 2);
printf("%s\n", s);
}
This is the output when building and running the code normally.
`û1*
`û1*2*
`û1*2*3*
`û1*2*3*4*
`û1*2*3*4*5*
Strings in C are a sequence of nonzero bytes followed by a terminating byte with a value of zero (the null-terminating byte, '\0').
You must size your buffer to have an additional space, to guarantee room for this null-terminating byte.
You must additionally make sure the contents of the buffer contain a valid string. You can do this by setting the first element of the buffer to the null-terminating byte, creating a zero-length string.
Failing to initialize the contents of your buffer means it will contain indeterminate values, and passing such a buffer to a function expecting a valid string will invoke Undefined Behavior.
The second argument to snprintf should be, at most, the size of the destination buffer.
Finally, consider using size_t when applicable, as it is the appropriate type for dealing with memory sizes (e.g., sizing variable-length arrays; the sizeof operator resolves to this type; snprintf expects this type as its second argument).
#include <stdio.h>
#include <string.h>
int main(void) {
size_t number_of_ints = 5;
char s[number_of_ints * 2 + 1];
char suffix[4];
s[0] = '\0';
for (size_t i = 1; i <= number_of_ints; i++) {
snprintf(suffix, sizeof suffix, "%zu*", i);
strncat(s, suffix, 2);
printf("%s\n", s);
}
}
You have a few issues with initialization and size of your buffers.
The size of your buffer is too short by 1 byte that is needed for 0-termination. Adding the last number causes buffer overrun and undefined behaviour.
In addition the calculated size is only sufficient as long as number_of_ints<10 because it only allows for single digit numbers.
That buffer is not initialized and us very likely not holding an empty string. Accessing it (via strcat etc.) invokes undefined behaviour.
The size you provide to snprintf is not related to the size of the buffer.
You should apply these changes:
#include <stdio.h>
#include <string.h>
int main(void)
{
int number_of_ints = 5;
char s[number_of_ints*2+1];
char suffix[4];
s[0] = 0;
for (int i = 1; i <= number_of_ints; i++)
{
snprintf(suffix, sizeof(suffix), "%d*", i);
strncat(s, suffix, 2);
printf("%s\n", s);
}
}
tbh I thought it wouldn't be hard to learn C seeing as I already know several other languages, but I'm having trouble with my code, and I can't seem to figure out how to fix these errors. I specialize in Python, so this is much different because of all the specifications for types, pointers, etc. Anyway, here's the code below, sorry, I would paste the error, but it won't allow me to copy paste. I was using some print functions and found the error to be coming from line 9, "*returnStr += *str";. Thanks in advance for any help.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
char *multiplyString(const char *str, int num){
char *returnStr = "";
for (int i = 0; i < num; i++){
*returnStr += *str;
}
return returnStr;
}
int main(void){
bool asking = true;
int height;
const char *symbol = "#";
while (asking == true){
height = get_int("How tall should the pyramid be? pick a number between 1 and 8: ");
if (8 >= height && height >= 1){
asking = false;
}
}
for (int i=1; i<=height; i++){
printf("%s %s\n", strcat(multiplyString(" ", height-i), multiplyString(symbol, i)), multiplyString(symbol, i));
}
}
Change multiplyString() to the following
char *multiplyString(const char *str, int num) {
// + 1 for null-terminator
char *returnStr = calloc(sizeof(*returnStr), strlen(str)*num + 1);
for (int i = 0; i < num; i++) {
strcat(returnStr, str);
}
return returnStr;
}
You were attempting to modify a string literal, which is forbidden in C. Secondly, += is not string concatenation in C; rather, it was trying to perform integer addition on the first character of returnStr.
To fix this, you dynamically allocate the proper amount of memory using calloc() (which also initializes the memory to 0, which is necessary for strcat()). Then, in each iteration, append the string using strcat() to the end of the new string.
Remember to free the strings returned by this function later in the program, as they are dynamically allocated.
Two problems:
First of all, returnStr is pointing to a string literal, which is really an array of read only characters. In this case an array of only a single character, being the string terminator '\0'
Secondly, *returnStr += *str; makes no sense. It's the same as returnStr[0] = returnStr[0] + str[0]. And since the destination (returnStr[0]) is a string literal, attempting to write to it leads to undefined behavior
If you want to create a new string containing num copies of str, then you need to create a new string containing at least num * strlen(str) + 1 characters, the +1 for the terminator. Then you need to use strcat to concatenate into that new string.
Also if you allocate memory dynamically (with e.g. malloc) then you need to make sure that the first element is initialized to the string terminator.
I got an assignment from my teacher to write a code that compares a given word to a bunch of words located in an array of strings.
If the word in the array is lexicography smaller than the word given, I need to put it inside a new array.
else, I'm moving to the next word.
for example;
given word: hello
arr=bus, alpha, world, java.
new array=bus,alpha.
I wrote a code that does that using STRCMP, but the computer throws me out when it gets to the strcpy part.
this is my code
char** LowerSTR(char* arr[], int size_arr, char* str, int* size_res)
size_res = 0;
char** newArr= (char**)calloc(size_arr, sizeof(char));
for (int i = 0; i < size_arr; i++)
{
if (strcmp(str, arr[i])==1)
{
for (int k = 0; k <size_arr;k++)
{
strcpy(newArr[k], arr[i]);
}
size_res++;
}
}
if (size_res == 0)
return NULL;
else return newArr;}
maybe I should use STRCAT instead?
please help :\
In calling strcpy with newArr[k] as an argument you're dereferencing a NULL pointer.
Recall that we allocate newArr as follows:
char** newArr= (char**)calloc(size_arr, sizeof(char));
There's actually multiple errors here. The first is that we calloc with sizeof(char) when we in fact want a region of char*s. So corrected1
we have
char** newArr= calloc(size_arr, sizeof(char*));
As we've calloc'd this piece of memory, all of it is zeroed. Thus when strcpy internally accesses newArr[k] (itself of type char*) it points to memory address 0, which is likely reversed by the OS, and in any case, not a valid address in the context of our program.
In order to resolve this, we need to allocate for each string. For instance, one might do
newArr[k] = malloc(strlen(arr[i]) + 1); // The +1 is for the \0 termination character
the line before we strcpy.
You also have a bug with size_res as you just treat it as an int instead of an int* as you need to dereference it when you want to change or read the value to which it points.
1 See here for why I've removed the cast.
You should scan newArr and print all strings inside, something like:
for (int i = 0; i < *size_res; i++) // !
{
printf("%s\n",newArr[i]);
}
(!) 'size_res' is passed to the function as a pointer to int,
So I'm doing a few practice questions for a final exam coming up. and I'm having a lot of trouble with dynamic memory.
So the question wants to basically parse through 2 different sources and compare them to find the similar words. (one from a csv file and one from a cgi input)
so I figured I'd use malloc/calloc to put a string in each array slot and then compare each slot. but I'm having some issues with my code:
char buffer[100],buffer2[100],tmp[100],line[100];
char *token,*tok,*input;
int main()
{
char s[100]="search=cat+or+dog+store";
char *search=(char*)calloc(10,sizeof(char));
strcpy(buffer,s);
sscanf(buffer,"search=%s",buffer);
int k=0;
tok=strtok(buffer,"+");
while(tok!=NULL)
{
strcpy(&search[k],tok);
k++;
tok=strtok(NULL,"+");
}
printf("%d\n",k);
strcpy(&search[k],"\0");
***printf("%s",&search[0]);
printf("%s",&search[1]);
printf("%s",&search[2]);
printf("%s",&search[3]);***
char* csv=(char*)calloc(10,sizeof(char));
char tmp2[100];
FILE *fp;
fp=fopen("web.csv","r");
while(fgets(line,sizeof(line),fp)!=NULL)
{
strcpy(buffer2,line);
token=strtok(buffer2,",");
while(token!=NULL)
{
strcpy(csv,token);
csv++;
token=strtok(NULL,",");
}
strcpy(csv,"\0");
free(csv);
free(search);
return(0);
}
the part i put between * * i put in order to test if the strings were put inside the calloc. but nothing prints out or smt weird prints out. the same code was used for the latter bottom part and they are both either empty or only printing out weird fragmented part of the code.
when i put the free(csv) and free(search), it says that "pointer being freed was not allocated". i looked it up but I can't seem to find a answer to why it does this?
thank you!
You seem to be trying to create an array of pointers. So let me show you what that looks like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXT 10
int main( void )
{
char s[100]="search=cat+or+dog+store";
char buffer[100];
char **search = calloc( MAXT, sizeof(char *) );
if ( sscanf( s, "search=%s", buffer ) != 1 )
return 1;
int t = 0;
char *token = strtok( buffer, "+" );
while ( token != NULL && t < MAXT )
{
search[t++] = token;
token = strtok( NULL, "+" );
}
for ( int i = 0; i < t; i++ )
printf( "%s\n", search[i] );
free( search );
}
Things to look for
search is declared as a char ** meaning pointer to a char pointer, which can be used like an array of char pointers
in the calloc, the allocation is for 10 items of type char *, i.e. an array of 10 pointers
in the sscanf, the input and output strings must not be the same string. I changed the arguments so that s is the input, and buffer is the output. Also, you should always check that the return value from sscanf is equal to the number of items requested.
in the while loop, I've added a check t < MAXT to avoid running past the end of the pointer array
search is an array of pointers, and strtok returns a pointer, so the line search[t++]=token; stores the pointer in the array. The string itself is still in the buffer.
This line here:
strcpy(&search[k],"\0");
What you are doing is adding the string literal "\0" to the k'th position in memory (which works... but gross). I believe you are trying to do this:
search[k] = '\0'
Notice the single quotes ('') that is a character rather than a string literal.
You should also not be casting a malloc: char *search = (char *)malloc(...)
MAINLY:
You should also consider that printf("%s", string) only prints up until the nearest terminator ('\0') in 'string'. Reference here.
So check what you are buffering, and see if you can build any new conclusions...
And, when you print your string, you only need to printf("%s", search)
I highly suggest you use malloc(), especially for strings. Because calloc() initiates all values to zero. And '\0' == 0, so you could be making it more difficult for yourself to diagnose.
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.