Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
It's a simple function for many but as a beginner, I've yet to overcome the pointer ghost specially when it comes to strings. I understand some of the examples of strcmp, strcpy, strlen as well as how the characters are assigned in the memory with a NULL terminator. I think I also get the point how a pointer variable in memory points to the address of a int var or char etc. and you assign them by dereferencing them to var/char, but whenever I try to write a code, the pointer ghost comes back to bite me.
So, here I'm trying to run this and doesn't work. I would appreciate if you could clarify this for me...
//GETNAME function should return a string that is not NULL and less than 20 characters
char getname (char *s1)
{
int i, n;
char s2[i];
printf ("Enter your name:" );
scanf ("%s", "s2");
if (s2 == NULL)
return 0;
else if(n<20)
for ( i=0, n =strlen (s2 + 1); i<n; i++)
*(s1+i) = s2[i]; //copy characters from s2 and point to chars of s1
return *s1;
}
int main (int argc, char *argv[])
{
char name[20];
char urname;
urname = getname(name);
printf (" Your name is : %s\n", urname);
getch();
return NULL;
}
Here are several errors; there may be more:
Uninitialized variable:
int i, n;
char s2[i];
i is not initialized here, yet you use it as if it was. What value should i have? Like this it is undefined behaviour.
Incorrect argument to scanf:
scanf ("%s", "s2");
The second parameter should be a pointer to the memory that you want the input to be written to, not a constant string. It should be:
scanf ("%s", s2);
Incorrect argument to strlen:
for ( i=0, n =strlen (s2 + 1); i<n; i++)
You want to add 1 to the string length not to the string itself, so it should be
for ( i=0, n = strlen(s2) + 1; i<n; i++)
General issues with getname, including return type:
char getname (char *s1)
Why is this function so complex? You could directly scanf into the parameter s1. You don't need s2 for anything. Also the return type is wrong. You return a pointer, not a single char. It should be:
char* getname(char *s1)
Not handling return value from getname properly:
char urname;
urname = getname(name);
getname returns a pointer to char, not a single char. It should be:
char* urname;
urname = getname(name);
As the previous post says that i is not initialised.
Also the line
scanf("%s", "s2");
Should be
scanf("%s", s2);
The lines
if (s2 == NULL)
return 0;
else if(n<20)
Is incorrect as s2 will not be NULL and n is not initialised
... That is for starters
I recommend you get a book and read it
Related
This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
Using printf with a non-null terminated string
(6 answers)
C - why is only char array null terminated? [closed]
(6 answers)
Closed 1 year ago.
If needed , you might run the example code below here:
Online C compiler
#include <stdio.h>
#include <string.h>
void foo(char *name);
char bar(char c);
int main(int argc, char **argv)
{
foo("Ashcroft");
return 0;
}
void foo(char *name)
{
printf("name = %s\n", name);
int name_length = strlen(name);
char code[name_length];
printf("length of name %d\n", name_length);
for (int i = 0; i < name_length; i++)
{
code[i] = bar(name[i]);
}
printf("length of code is %ld\n", strlen(code));
printf("name is %s\n", name);
}
char bar(char c)
{
return 'a';
}
Problem
I expected length of code to be the same as length of name,
but somehow the length changes after the for loop.
Output
name = Ashcroft
length of name 8
length of code is 14
name is Ashcroft
Update
tried char code[name_length+1]; but the result is still the same
You declared code to be just long enough to hold the characters that are part of the string in name, but not enough to hold the terminating null byte that strings end with.
So when you pass code to strlen and printf, they read past the end of the array looking for the terminating null byte. Reading off the end of an array triggers undefined behavior which in this case manifests as an unexpected length for the string.
You need to make code one element longer to hold the terminating null byte:
char code[name_length+1];
And also add the null byte after building the string:
int i;
for (i = 0; i < name_length; i++)
{
code[i] = bar(name[i]);
}
code[i] = 0;
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have been working on my C assignment where I try to replicate strlen() function without actually using it. This is the code I have been trying to get working. However, somehow the main function does not reflect what's happenning in mystrlen() function. Can you please tell me why it does not work as the strlen() function?
#include <stdio.h>
int mystrlen(char *input_string) {
/* This function returns the length of the input string */
/* WRITE FUNCTION CODE HERE! */
char str1[50];
int abcd = 0;
scanf("%s", str1);
int m;
for(m=0; str1[m]; m++){
abcd ++;
}
return 0;
}
int main(int argc, char **argv) {
int length;
if (argc!=2) {
printf("Usage: strlen <input_string_with_no_space_inside_it>\n\n");
return 1;
}
length = mystrlen(argv[1]);
printf("The length is: %d characters.\n",length);
return 0;
}
This:
return 0;
should be:
return abcd;
That said, abcd is a terrible name for this variable, and the function makes little sense as a strlen() replacement. It doesn't touch its argument, and calls scanf() to read input from the user, which you really don't want a strlen() replacement to do.
Here's one way of writing it:
size_t mystrlen(const char *s)
{
size_t len = 0;
if(s != NULL)
{
while(*s != '\0')
{
++len;
++s;
}
}
return len;
}
Improvements include:
Proper size_t-typed return value (lengths are sizes, and cannot be negative) so size_t is proper and what the real strlen() uses.
Doesn't do any input-reading.
Uses the input argument.
Computes length and returns it.
It also handles being given NULL, as a bonus.
A matching main() that does what yours did could be:
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: strlen <input_string_with_no_space_inside_it>\n\n");
return 1;
}
const size_t length = mystrlen(argv[1]);
printf("The length is: %zu characters.\n", length);
return 0;
}
This basically centers around the int-to-size_t change. Also note that in shells supporting quoting, you can run your program like this:
$ ./strlen "hello this is a string with spaces in it"
and it will pass that entire quoted string (sans quotes, of course) in argv[1].
First of all, you try to pass a string, and then you invoke scanf function in mystrlen. Delete this scanf.
Secondly, your function always returns zero instead of value of variable abcd.
I need to get strings dynamically but as I need to get more than one string, I need to use functions. So far I wrote this
(I put //**** at places i think might be wrong)
char* getstring(char *str);
int main() {
char *str;
strcpy(str,getstring(str));//*****
printf("\nString: %s", str);
return 0;
}
char* getstring(char str[]){//*****
//this part is copy paste from my teacher lol
char c;
int i = 0, j = 1;
str = (char*) malloc (sizeof(char));
printf("Input String:\n ");
while (c != '\n') {//as long as c is not "enter" copy to str
c = getc(stdin);
str = (char*)realloc(str, j * sizeof(char));
str[i] = c;
i++;
j++;
}
str[i] = '\0';//null at the end
printf("\nString: %s", str);
return str;//******
}
printf in the function is working but not back in main function.
I tried returning void, getting rid of *s or adding, making another str2 and tring to strcpy there or not using strcpy at all. Nothing seems to working. Am I misssing something? Or maybe this is not possible at all
//Thank you so much for your answers
Getting the string part can be taken from this answer. Only put a \n as input to the getline funtion.
char * p = getline('\n');
Three things :-
don't cast malloc, check if malloc/realloc is successful and sizeof is not a function.
The problem is not with the function that you are using, but with the way you try copying its result into an uninitialized pointer.
Good news is that you don't have to copy - your function already allocates a string in dynamic memory, so you can copy the pointer directly:
char *str = getstring(str);
This should fix the crash. A few points to consider to make your function better:
main needs to free(str) when it is done in order to avoid memory leak
Store realloc result in a temporary pointer, and do a NULL check to handle out-of-memory situations properly
There are two things to take away from the lesson as it stands now:
(1) You should have one way of returning the reference to the new string, either as an argument passed by reference to the function OR as a return value; you should not be implementing both.
(2) Because the subroutine your teacher gave you allocates memory on the heap, it will be available to any part of your program and you do not have to allocate any memory yourself. You should study the difference between heap memory, global memory, and automatic (stack) memory so you understand the differences between them and know how to work with each type.
(3) Because the memory is already allocated on the heap there is no need to copy the string.
Given these facts, your code can be simplified to something like the following:
int main() {
char *str = getstring();
printf( "\nString: %s", str );
return 0;
}
char* getstring(){
.... etc
Going forward, you want to think about how you de-allocate memory in your programs. For example, in this code the string is never de-allocated. It is a good habit to think about your strategy for de-allocating any memory that you allocate.
Let's simplify the code a bit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getstring()
{
char c = 0;
int i = 0, j = 2;
char *str = NULL;
if ((str = (char*) malloc(sizeof(char))) == NULL)
return NULL;
printf("Input String: ");
while (c = getc(stdin)) {
if (c == '\n') break;
str = (char*) realloc(str, j * sizeof(char));
str[i++] = c;
j++;
}
str[i] = '\0';
printf("getstring() String: %s\n", str);
return str;
}
int main()
{
char *str = getstring();
printf("main() String: %s\n", str);
free(str);
return 0;
}
Then execute:
$ make teststring && ./teststring
cc teststring.c -o teststring
Input String: asdfasfasdf
getstring() String: asdfasfasdf
main() String: asdfasfasdf
This question already has answers here:
Return char[]/string from a function [duplicate]
(5 answers)
Closed 8 years ago.
I am writing a program that returns a string from stdin, but i am getting warning that it returns an adress of local wariable. How can i return the string?
thanks in advance
#include <stdio.h>
char* readLine()
{
int i;
char input[1024];
for(i=0;i<1024;i++)
{
input[i]=fgetc(stdin);
if(input[i]=='\n')
{
break;
}
}
return input;
}
int main()
{
printf("%s",readLine());
return 0;
}
This should work for you:
You can pass input from main as reference:
#include <stdio.h>
char * readLine(char * input, int length) {
int i;
for(i = 0; i < length; i++) {
input[i] = fgetc(stdin);
input[length] = '\0';
if(input[i] == '\n')
break;
}
return input;
}
int main() {
int length = 1024;
char input[length+1];
printf("%s", readLine(input, length));
return 0;
}
Try to do something like that instead:
#include <stdio.h>
char* readLine()
{
int i;
char *input;
if ((input = malloc(sizeof(char) * 1024)) == NULL)
return (NULL);
for(i=0;i<1024;i++)
{
input[i]=fgetc(stdin);
if(input[i]=='\n')
{
input[i] = '\0';
break;
}
}
return input;
}
int main()
{
char *str;
if (str = readLine()) != NULL) {
printf("%s\n", str);
free(str);
}
return 0;
}
}
There is nothing wrong here - that is just a WARNING because usually it is a common mistake of new programmers. I used to run into problems with this usage all the time.
The first thing... this "string" is not null-terminated. You'll want to put at the end of that function something like *(input + i) = '\0'; and make either the array size 1025 or the condition i < 1023 (so that the null character isn't assigned beyond the end of the buffer), because at the moment using this array in a function that expects null termination will cause it to possibly continue past the end of the array, resulting in a memory access violation. Alternately, you could use memset(input,0,1024);, just still make sure that the condition is something like i < 1023 so that the standard input you receive doesn't end up writing all the way to the last null character in the array.
The other problem is that this memory is local, as in it "belongs" to this function. And for the usage you have here, it is probably just fine to use the same memory... if you plan to call the function, do something with the result, and then call the function again, do something with the result... But if you want to keep what's given to you by it, you'll have to either (1) copy the string to another buffer that isn't going to be written to again when the function is called in the future, or (2) make the function allocate a new buffer each time it runs, and then be sure to delete that memory when you're done with it. For example, instead of char input [1024]; (which by the way would have the same pointer for the life of the program, so it's not really necessary to return it each time) you could write char* input = malloc(1024); and later, when the caller is done with the string, you should free(input);. (Of course, the name might not be input in this case since you would probably not want to free the memory in the function whose purpose is to allocate it.)
I will edit this later with code showing changes.
What I am trying to do is to break the user input in parts with whitespace as a delimiter, copy the parts into the array (tokenAr) and compare the tokenAr[0] (the first part) if it is equal to sHistory. if they are equal, check the value of tokenAr[1] if it is "1", "2" etc, to execute the corresponding command that is entered in the history array. This is what i have tried to far and it crashes. I am using TCC on Windows x64.
EDIT: I forgot to mention that I began learning C, just two days ago.
EDIT2: I run the program in a debugger and it has raised an Acces Violation(Segmentation Fault) in line if(strcmp(tokenArPtr[0],sHistory)==0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1; int j=1; int k=0;
char history[100][100] = {0};
char sKey[] = "exit";
char sInput[100];
char sHistory[]="history";
do
{
//gather user input
printf ("hshell> ");
fgets (sInput, 100, stdin);
strcpy(history[i],sInput);
i++;
//END_gather user input
//Tokenizing
char delims[] = " ";
char *tokenArPtr[5];
char *result = NULL;
result = strtok(sInput, delims);
tokenArPtr[0] = result;
while (result!=NULL)
{
puts(result);
result= strtok(NULL, delims);
tokenArPtr[k+1] = result;
puts(tokenArPtr[k]);
puts("=====");
k++;
}
k=0;
/*
//END_Tokenizing
if(strcmp(tokenArPtr[0],sHistory)==0)
{
for(j=1;j<i;j++)
{
printf("%d. %s \n",j,history[j]);
}
}
else if (strcmp (sKey,tokenArPtr[0]) != 0)
{
printf("\nCommand not found \n");
}*/
}while (strcmp (sKey,sInput) != 0);
return 0;
}
EDIT 3: I used the result variable instead of the tokenArPtr directly, but when debugging, I noticed that the values of the array are not being updated.
Which type does strtok return? char *. What is the type of tokenAr[k]? char. What type does strcmp expect as input? char * and char *. What is the type of tokenAr[0]? char.
See a problem? You should. The * is pretty significant.
Assuming tokenAr is declared like char *tokenAr[2];, how many char * values can tokenAr store? What happens when k exceeds 2? You need to ensure you don't overflow your tokenAr array.
history is uninitialised. Using an uninitialised variable is undefined behaviour. I suggest initialising it, like this: char history[100][100] = { 0 };
Which book are you reading?
While tokenizing, the loop will never end because the test is on the variable "result" that will never change... So you're finally going to a buffer overflow with "tokenAr"... Modify your code to test "tokenAr".
Edit: And tokenAR should be an array... (I don't know how it can compile...)
There are many problems... First of all you should include string.h which will show you some errors in compilation.
I believe that the main problem is here:
char tokenAr[2];
result = strtok(sInput, delims);
while (result!=NULL)
{
tokenAr[k] = strtok(NULL, delims);
k++;
}
tokenAr should be an array of pointers, not chars. And are you sure that k will never exceed 2? An assertion would help debugging.