This is my task from school:
Write a function insertString that inserts the string s2 into s1 at index n.s1 has been allocated using malloc and should be resized (the function is void again).
The program gave me a NULL on PC and when I switched to the phone the compilor said my realloc has a invalid pointer. But I really don't know what I did wrong.
Here is the code:
void insertString(char *str1, char *str2, int n){
int lengStr2=strlen(str2);
printf("%d %d ", lengStr2,n);
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
str1=(char*)realloc(str1,lengStr2+n+1);
if (str1==NULL){
printf("Error\n");
free(str1);
return -1;
}
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
memcpy(str1+n,str2,lengStr2+1);
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
}
void testInsertString( char *str2, int n, char *expect){
char*str1=(char*)malloc(3*sizeof(char));
str1="hoi";
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
insertString(str1,str2,n);
printf("--> result:%s --> ",str1);
(strcmp(str1,expect)==0)?printf("Success"): printf("Failure");
free(str1);
printf("\nIs Free\n");
}
Here the output:
str1= hoi, str2: Hallo, n: 1 5 1
str1= hoi, str2: Hallo, n: 1 Error
--> result:hoi --> Failure
Is Free
Process returned 0 (0x0)
Please if you know what I did wrong can you show me the correct version? Even so I have the problem that I can't right a program right just by reading a text, I need to see how it should be written. So I need to see the right result to learn from the mistake ^^" (that's why some stuff in school is for me really hard). Thanks in advance ^^
char *str1 = malloc(3*sizeof(char)); /* Allocate memory */
str1="hoi"; /* Discard the only reference to the allocated memory */
The above two lines are similar in spirit to:
int x = 5;
x = 7;
You need to copy the string "hoi" into the newly allocated memory, and you need to allocate at least 4 bytes to hold the string "hoi". For example:
char *hoi = "hoi";
char *str1 = malloc(strlen(hoi) + 1);
if( str1 == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
sprintf(str1, "%s", hoi);
Here is a fixed version :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Changing the signature to return the reallocated ptr would be safer
char * insertString(char *str1, char *str2, int n){
int lengStr2=strlen(str2);
//because str1 could differ from the received ptr after reallocation
str1=(char*)realloc(str1,lengStr2+n+1);
if (str1==NULL){
printf("Error\n");
return NULL;
}
strcpy(str1+n,str2);
return str1; // So we return the new ptr to the caller
}
void testInsertString( char *str2, int n, char *expect){
char*str1=(char*)malloc(6*sizeof(char)); // The null termination must be counted
strcpy(str1, "Hello"); // You should use strCpy here instead of =
str1 = insertString(str1,str2,n); // Refreshes the ptr
printf("\n--> result:%s --> ",str1);
(strcmp(str1,expect)==0)?printf("Success"): printf("Failure");
free(str1);
}
int main() {
testInsertString(" World", 5, "Hello World"); // --> result:Hello World --> Success
return 0;
}
Related
I'm trying to write a program to split a string into the first 3 characters, the next 3 characters, and then the last 3 characters for the specific string.
int main(int argc, char *argv[])
{
char str[9] = "AbcDefGhi";
char first[3], second[3], third[3];
int ret;
ret = sscanf(str, "%3s%3s%3s", first, second, third);
printf("# variables: %i\n", ret);
printf("1: %s\n", first);
printf("2: %s\n", second);
printf("3: %s\n", third);
printf("whoops");
return 0;
}
But when I run it, the output is
# variables: 3
1: AbcDefGhi
2: DefGhi
3: Ghi
whoops
And I want
# variables: 3
1: Abc
2: Def
3: Ghi
whoops
Any help is appreciated.
man scanf:
String input conversions store a terminating null byte ('\0') to mark the end of the input; the maximum field width does not include this terminator.
That is, the buffer to store the string needs to be at least one byte larger than the maximum field width to account for the NUL terminator. So increase the size of all your arrays to account for the NUL terminator.
char str[] = "AbcDefGhi";
char first[4], second[4], third[4];
I'm not sure if you need to do it without any functions from libraries, but I have created a code that is doing exactly what you want.
Let us know if it's to complicated for you.
#include <stdio.h>
#include <stdlib.h>
char *split(const char *str, size_t size){
static const char *p=NULL;
char *temp;
int i;
if(str != NULL) p=str;
if(p==NULL || *p=='\0') return NULL;
temp=(char*)malloc((size+1)*sizeof(char));
for(i=0;*p && i<size;++i){
temp[i]=*p++;
}
temp[i]='\0';
return temp;
}
int main(){
char *p = "AbcDefGhi";
char *temp[5];
int i,j;
for(i=0;NULL!=(p=split(p, 3));p=NULL)
temp[i++]=p;
for(j=0;j<i;++j){
printf("%d: %s\n",j, temp[j]);
free(temp[j]);
}
printf("whoops");
return 0;
}
I have done one MCVE code of passing char pointers into other function. I have the dude if both ways of passing char pointer parameter are equal (how str1 and str2 are passed into passingCharPointer1 and passingCharPointer2 respectably).
Also, I have include comments inside code with the behavior of the free/null functions and their behavior (I would appreciate it if they were also read).
The code is:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 50
void passingCharPointer1(char *str) {
strcpy(str, "Hi-1!");
}
void passingCharPointer2(char **str) {
strcpy(*str, "Hi-2!");
}
int main() {
// Init char pointers
char *str1 = malloc((MAX_LENGTH +1)*sizeof(char));
char *str2 = malloc((MAX_LENGTH +1)*sizeof(char));
// Gets their values
printf("Input string 1: ");
fgets(str1, MAX_LENGTH , stdin);
printf("Input string 2: ");
fgets(str2, MAX_LENGTH , stdin);
printf("\n");
// Remove '\n' character
str1[strcspn(str1, "\n")] = '\0';
str2[strcspn(str2, "\n")] = '\0';
// Print their values
printf("BEFORE - Function 1: %s\n", str1);
printf("BEFORE - Function 2: %s\n", str2);
// Pass to function in two ways - ARE BOTH WAYS EQUAL?
passingCharPointer1(str1);
passingCharPointer2(&str2);
// Print their values
printf("AFTER - Function 1: %s\n", str1);
printf("AFTER - Function 2: %s\n", str2);
// Freeing pointers
free(str1);
free(str2);
// Print their values after freeing
printf("\nAFTER FREE 1: %s\n", str1); // Show rare characters (I supposse it is normal behaviour after free)
printf("AFTER FREE 2: %s\n", str2); // Continue having its content (I supposse it is not normal behaviour after free)
// Nulling pointers
str1 = NULL;
str2 = NULL;
// Print their values after nulling
printf("\nAFTER NULL 1: %s\n", str1); // Normal behaviour
printf("AFTER NULL 2: %s\n", str2); // Normal behaviour
// Exit success
return 0;
}
In general the functions are not equivalent. The first function accepts pointer by value while the second function accepts pointer by reference. As result the second function can change the original pointer used in an expression as the argument.
Consider the following demonstrative program
#include <stdio.h>
void passingCharPointer1( char *s )
{
s = "Bye";
}
void passingCharPointer2( char **s )
{
*s = "Bye";
}
int main(void)
{
char *s1 = "Hello";
char *s2 = "Hello";
printf( "Before function calls: %s %s\n", s1, s2 );
passingCharPointer1( s1 );
passingCharPointer2( &s2 );
printf( "After function calls: %s %s\n", s1, s2 );
return 0;
}
Its output is
Before function calls: Hello Hello
After function calls: Hello Bye
Pay atttention to that accessing memory after it was freed invokes undefined behavior.
If you question is truly:
is equal both ways of passing parameters (function1 and function2)
(and you ignore all of the code in main()), then yes, the two functions are essentially equivalent.
The difference is that function1 takes a pointer to a char (which, in the C language, is an idiom for a string) and function2 takes a pointer to a pointer to a char.
But as #Vlad from Moscow points out, function2 allows you to modify the pointer passed into the function.
So, my goal is to create a linear search, but i have got that down pat, I am having one problem with accessing strings from the struct, that i have stored using a txt file, so in linearSearch() I tried doing this:
printf("Name: %s \n", q.name[i]);
printf("Data: %d \n", q.data[i]);
The data would be perfect but name would just print out the same name for every array which would be the last item that I put into the array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* name[10];
int data[10];
}Word;
//int bubblesort (Word word);
void linearSearch(char* name, Word q);
int main (int argc, const char *argv[]){
Word q;
char username[9]; /* One extra for nul char. */
int score;
int i = 0;
FILE *ifp, *ofp;
ifp = fopen("Data.txt", "r");
while (fscanf(ifp, "%s %d", &username, &score) == 2) {
q.name[i] = username;
printf ("Name: %s, I = %d \n", q.name[i], i);
q.data[i] = score;
printf ("Data: %d, I = %d \n", q.data[i], i);
i++;
}
linearSearch("Matt", q);
return EXIT_SUCCESS;
}
void linearSearch(char* name, Word q){
int i = 0;
int foundIt = 0;
int numNames = sizeof(&q.name);
while ((foundIt == 0) && (i <= numNames)){
printf("Name: %s \n", q.name[i]);
printf("Data: %d \n", q.data[i]);
if ((strcmp(name, q.name[i]) != 0)){
i = i + 1;
} else {
foundIt = 1;
}
}
if (foundIt == 1){
printf("Name found at position %d", i);
} else {
printf("Required person not found");
}
}
This happens because of the code
q.name[i] = username;
You cannot assign the value of an array using = operator. Here, you're assigning the address of username to every q.name[i]. So, the last value of username is reflected throughout the array.
What you actually need is to use malloc() to allocate memory and then strcpy() to copy the string contents.
Otherwise, you can also make use of strdup().
Either way, don't forget to free() the allocated ememory once you're done using them.
I can see that you declared char username[9], so I assume your names should be at most 8 characters long. You should :
read with : fscanf(ifp, "%8s %d",&username, &score) == 2 : the & is useless in front of an array (it decays nicely to a pointer), but you should limit size of input - ok , your problem does not come from there
use a 2D char array for Word.name instead of an array of pointers. That way your memory is already allocated and you can safely strcpy to it :
typedef struct {
char name[10][9];
int data[10];
}Word;
then :
strcpy(q.name[i], username); /* safe because qname[i] and username are both [9] */
The rule here is always control that you do not risk a buffer overrun when writing in char arrays/
An alternative way would be to do dynamic allocation through strdup but in that case you should free it.
I had a code which works fine with the integers
#include<stdio.h>
int main()
{
int i;
int* p[5];
printf("Enter the elements to be shorted");
for(i=0;i<=4;i++)
{
scanf("%d\n",&p[i]);
}
for(i=0;i<=4;i++)
{
printf("entered [%d] integers are = %s",i, p[i]);
}
return 0;
}
produce a output
Enter the strings to be shorted1
2
3
4
5
6
enetered [0] string is = 1
enetered [1] string is = 2
enetered [2] string is = 3
enetered [3] string is = 4
enetered [4] string is = 5
but when i change limne int* p[5] to char* p[5] for using it as array of pointers to string and do the necessary changes in the above code, it produces segmentation fault.I read ian a book that we cant do this as some garbage value will be assigned to the array of pointers to string.So what can be the possible way to implement the above code with array of pointers to string.
what i want to do is get the strings as input from users and store them in array of pointers to string and then get them printed at initial stage.I am trying to code for simplest string shorting.
Make sure you reserve room for the characters of the strings:
char p[5][128];
and also make sure you limit the length when reading, so scanf() doesn't write outside the buffer:
if(scanf("%127s", p[i]) == 1)
{
p[i][127] = '\0'; /* Make sure it's terminated. */
}
First of all, the int array definition is wrong in your first test. it should be
int p[5];
Second you have to allocate memory for each pointer in your array. each element in your array char *p[5]; is a pointer.
You can use directly by scanf
char *p[5];
for(i=0;i<=4;i++)
{
scanf("%ms\n",&p[i]);
}
But this is not portable is available only for gcc>gcc2.7
or you have to allocate memory each time before scanf()
char *p[5];
for(i=0;i<=4;i++)
{
p[i]=calloc(100,1);
scanf("%99s\n",p[i]);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
int i;
char *p[5];
printf("Enter the string\n");
for(i=0;i<=4;i++){
char buff[128];
scanf("%127s", buff);
p[i] = strdup(buff);
}
for(i=0;i<=4;i++){
printf("entered [%d] string is = %s\n", i+1, p[i]);
}
for(i=0;i<5;++i) free(p[i]);
return 0;
}
I am a newbie in c programming language and I have a university tutorial assignment that is related with working with chars(I wont be graded for this assignment) where you have to count words, I have to compile and submit my answers in an online web environment where my code will run against test cases that are not visible to me.here is my assignment:
Write the function 'wc' which returns a string containing formatted as follows: "NUMLINES NUMWORDS NUMCHARS NUMBYTES" .
Whitespace characters are blanks, tabs (\t) and new lines (\n). A character is anything that is not whitespace. The given string is null-char (\0) terminated.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* wc(char* data) {
char* result ;
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
char* empty=NULL;
while(strstr(data,empty)>0){
numWords=1;
for (i = 0; i < sizeof(data); i++) {
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
this code will give me the correct output result but I am missing something here at least the test tells me that.
You've got a very serious error:
char* result;
...
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
This is not allowed in C. You need to allocate sufficient memory for the string first. Declare result as a large enough static array, or use malloc if you've covered that in your course.
e.g.
char buf[100]; // temporary buffer
sprintf(buf, "%d %d %d %d", numLine, numWords, numChars, numBytes);
char *result = malloc(strlen(buf) + 1); // just enough for the string
strcpy(result, buf); // store the string
return result;
What if you have this input?
Two Words.
You have to count the transitions between whitespace/non-whitespace, not just count spaces.
Also, I'm pretty sure strstr(data,NULL) will not do anything useful.
You also appear to be missing the \t for tab in your white space checker, and you're not correctly checking when you're in or out of a word. You can use the boolean type bool for this defined in stdbool.h for this.
Source code of wc unix command:
http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html
All test cases handled.
1) sizeof is wrong:
Instead of sizeof operator you need to use strlen() in for loop, like:
for (i = 0; i < strlen(data); i++)
^ not sizeof
sizeof(data) returns only size of data pointer address that is 4. Because you are to read all char in data[] you need strlen() that will return length of data[] (or number of chars in data[])
2) memory error:
Next Error I can notice there is no memory allocated for result. it declare like:
char* result ;
and No memory allocate! and you are writing using sprintf that cause undefined behavior of your code
3) while(strstr(data,empty)>0) is wrong
strstr() search position of a string in to other you empty string is NULL , CHECK:
char *strstr(const char *s1, const char *s2);
you strstr() always returns data, Why are you calling this? I believe you don't need this while() loop.
I improved you code upto some extend as below, There was only three error as I mentioned above now corrected(to understand read comments), You basic algo is correct:
#define SIZE 256 // added size macro
char* wc(char* data)
char* result = malloc(SIZE*sizeof(char)); //(2) allocated memory for result
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
numWords=1;
// (3) remove while loop
for (i = 0; i < strlen(data); i++) { //(1) change size
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
int main(){
printf("\nresult: %s\n", wc("q toei lxlckmc \t \n ldklkjjls \n i \t nn "));
return 1;
}
Output:
result: 2 14 28 41