Why printf doesn't show correctly my array? - c

I have a little problem working with pointers and arrays. The trouble lies on I have a function which creates a new array from the original one, choosing the appropiate characters from a period passed from a parameter. Here is the protype:
char *get_string_period(char chain[], uint8_t period);
I've used a pointer to that array I want to return because I can't return my new array of characters itself. So I save in main.c this pointer into a variable and I do a printf:
char *ptr = get_string_period(chain, period);
printf(“The string of the new array is %s”, ptr);`
But printf shows a short version of my generated array. If I print from the function I get:
vtvfnstrtmwiapjhqsblzgtiapyogiytzhvuswzsfevpsdbljjgmfwoikuvfmoeotwsjwtgussmbegvlxjutktmkzvvvttwlyeqhuwk
From main.c:
vtvfnstrtmwiapjhqsblzgti��j
How can I solve it?
One question more: how can I reuse this array passing it to another function whose parameter is an array itself (char chain[ ])?
Thanks in advance.

Probably get_string_period returns a char pointer to a local variable, so when the function returned, what it actually returned will point to an invalid address.
Instead of outputting some garbage value, sometimes a segmentation fault occurs in situations like this.

A char array is terminated by a null byte. That's how printf statement works. It looks for the null byte to end the char array. if your char * doesn't have null byte, printf will keep printing as long as it can.

Related

How can I Initialize a global 1D array of type char with a number?

Initialize a global 1D array "StudentData" of type char with your ID (5 digits).
Using pointers syntax is mandatory in this part.
Can you give me some tips about doing that?
I tried doing this,
char *StudentData;
void loadData(){
StudentData=(char*)"60897";
}
Is it right or should I try doing something else?
You probably want something along the lines of:
#include <string.h> //This header has strcpy()
#define ENOUGH_DIGITS 5 //This is so you can easily modify ID length in the future
char StudentData[ENOUGH_DIGITS+1]; //Global array 1 bigger than the longest string
void loadData(){
//Ask the compiler to put a read-only string somewhere in the data memory
const char *myID = "60897";
//Copy the read-only string into the global array
strcpy(StudentData,myID);
}
While you are indeed using an array (the string literal actually is one), it is an anonymous one – and your studentData is only a pointer to that one.
a global 1D array "StudentData"
I would rather interpret this as you are intended to have a true array with that name, so that would look like:
char studentData[N];
where N is a constant expression representing an appropriate size for your array, at least 5 as you need to be able to store 5 digits – possibly 6 if your ID should be represented as a C-string (such one needs one additional character holding the mandatory null-terminator!), or you go with a power of two right away (8 minimally).
Using pointers syntax is mandatory in this part.
So you'll need a pointer to that array:
char* ptr = studentData;
You could now just use the pointer to assign values to:
*ptr++ = '0'; // dereferences the pointer, assigns a value to (in this
// case a character representing the digit zero) and
// increments it afterwards to point to the next character
// repeat this for the next four digits!
*ptr++ = 0; // terminating null character (note: no single quotes)
// or:
*ptr = 0;
// it's up to you to decide if incrementing yet another time actually
// is meaningful (first variant) or unnecessary (second variant)...
If there are no further requirements given you might have this code directly in main function or as a little bonus place it in another function being called from main like:
void loadData(size_t size, char data[size])
{
// ideally size check with appropriate error handling
// assignment as above
}
// in main:
loadData(sizeof(studentData), studentData);
Note: For function parameters all of char* data, char data[] or char[someArbitrarySize] are equivalent, if any size is given, it is simply ignored – we still can add it for documentation purposes, in above signature: to tell that an array with a size of (at least) size is expected. Note, too, that if there are more than one dimensions given this only applies for the outer most dimension, though!
1D array "StudentData"
No no no. StudentData is not an array, it's a pointer. Arrays are blocks of memory while pointers are addresses to memory, which may or may not be an array. An array sometimes becomes a pointer, that's called decay.
"60897" is already a char * compatible. You can directly assign it to StudentData. Like this:
StudentData = "60897";
If you want to use an array, do this:
#include <string.h>
char StudentData[WHATEVER_IS_ENOUGH_TO_HOLD_THE_DATA]; /* allocate array.
make sure that the size of the array accounts for the null
terminating character. */
void loadData(){
strcpy(StudentData, "60897"); //you can't directly assign to an array.
}

CS50.h segmentation fault if memory is not allocated to string

While working on a CS50 problem set (substitution), I encountered a segmentation fault when running the code. After some searching I found out that assigning memory (malloc) to string "output" fixes the issue. However I wanted to understand why assigning memory is necessary here?
Any explanation would be appreciated.
code extract: -please note i am using the cs50.h library
string cipher(string input, string key) {
string output=malloc(strlen(input)+1);
for (int i=0, len = strlen(input); i<len; i++) {
if(isalpha(input[i]) != 0) {
output[i] = substitute(input[i], key);
}
else {
output[i] = input[i];
}
}
return output;
free(output);
}
As much as I could know about CS50.h string, I came to know that
string output
is just declaring a character pointer named output. So what actually happens in your code is that until you explicitly declare the "strlen(input)+1" contiguous memory locations beloging to output only, they are essentially free locations for the program. Hence, your output pointer will contain only the character at the 0th index. The function returns what "output" actually is, a pointer. Some process within the program meanwhile may make use of all the other memory locations other than output[0], since they never belonged to output string. output only pointed to the first character of some string.
Bound checking in C, C++ is essentially done by the programmer. output[i] for any arbitrary i will never give an error because it's a simple pointer arithmetic for the programmer, i.e. output[i] = *(output+i).
:)
For starters this statement
free(output);
never gets the control because it is placed after the return statement
return output;
and moreover it does not make a sense. It is the caller of the function that is responsible to free the allocated memory.
You need to dynamically allocated memory because otherwise if you will declare a variable length array like
char output[strlen(input)+1];
then after exiting the function it will not be alive and an attempt to access the array outside the function results in undefined behavior.
That is if you will just write
string output;
that is equivalent to
char *output;
then the pointer output has indeterminate value because it was not initialized and neither memory was allocated where the source string will be copied.
You could change the source string input in place without creating one more array.
In this case it would be enough to write
if(isalpha(input[i]) != 0) {
input[i] = substitute(input[i], key);
}
and then you could place the statement
return input;
Pay attention to that using the alias string for the type char * is a bad idea.
The function declaration if to rewrite it like
char * cipher(char *input, char *key);
is confusing. It is unclear whether the strings input and key are being changed within the function or not.
If you want that the function returns a new string build from the source string then the function declaration should look like
char * cipher(const char *input, const char *key);
Thus answering your question
However I wanted to understand why assigning memory is necessary here?
if you want to create a new string from the source string pointed to by the pointer input then it is evident that you need to allocate a new character array where elements of the source string will be copied.
Otherwise if you want to change the source string in place then there is no need to create one more array.

2D array of strings in C:

I have been working with C for the first time in a long time and one of the biggest problems for me has been working with strings, since they aren't expressed as well as they are in Python.
From what I know and understand, a char * is just a pointer to a string(or rather, the first character in a string). A char[] is very similar and can be used the same way.
My first question is a little side question, but while we use it to execute the same things, is there a difference in correctness or how the compiler views it?
Going ahead, I know that char *[] is just an array, but each element is a pointer of type char *. So through that each element when deferenced/accessed would just return a string. Which is why char *argv[] just takes values from command line.
For a problem that I was working on I needed a a 2D array of strings and had been trying to run it is char *[][] and making function calls for it.
I have a function type defined as void runoff_function(candidates *, int a, int b,char * array[a][b]); That expects a 2D array of character pointers.
My main function has a variable defined and populated as char* list[n][argc];
Except when running a loop to initialize user inputs:
char* list[n][argc];
for(int i=0;i<n;i++)
{
printf("Voter %d\n",(i+1));
for(int j=1;j<argc;j++)
{
printf("Rank %d\t",j);
scanf("%s",list[i][j-1]);
}
I get a seg fault after my first input and I don't know why.
The declaration char* list[n][argc]; reserves space for the string pointers, only. However, each string needs a place to store its characters. You must supply this space.
The easiest and safest way to do it, is to instruct scanf() to allocate some space on the heap for your string. This is done by adding the "m" modifier to the "%s" conversion. scanf() will then expect a char** as the argument, and store the pointer to a new string at that location. Your code would look like this:
scanf("%ms", &list[i][j-1]);
Note that it is your job to subsequently get rid of the memory allocations. So, once you are done with your strings, you will need to add a loop that calls free() on each cell of the 2D array:
for(int i=0;i<n;i++) {
for(int j=1;j<argc;j++) {
free(list[i][j-1]);
}
}
The "%ms" format is specified by the POSIX.1-2008 standard, so safe to use on any modern linux.

C: twist char *

Note: I can't use any libs or includes!
I have the following Code:
void twstng(char * str, int end, int strt) {
if(strt != end && strt != end-1) {
int hlp = str[strt];
printf("strt %d end %d hlp %d\n", strt, end, hlp);
str[strt] = str[end-1];
printf("test\n");
str[end-1] = hlp;
printf("test\n");
twstng(str, strt+1, end-1);
}
}
and in the main function:
char * sol = "hello";
twisting(sol, 5, 0);
I want to twist the entire string. But the console shows:
strt 0 end 4 help 104
And then comes a memory access error. But why?
My second problem is, that in the original task the given string is a
const char * const str
How can I work with it in the twstng function?
Your char *sol is a pointer to the string "hello". Being a string literal, it is actually read-only, and thus when you pass the pointer to your function, you get an error when you modify the contents of the constant string "hello" through the pointer.
Regarding the second part of the question, const char * const (i.e., constant pointer to a constant char) would indeed be a better type for the pointer, as it would convey that the thing pointed to is constant. However, then you cannot pass this pointer to the function (because the function takes a pointer to a non-const char), and it is not clear from the information given how you are "allowed" to work around this. One way is to copy the string and modify the copy.
edit: And as pointed out by other answers, your recursive call mixes up the start and end arguments (by using the more logical order of start first).
In C all string literals are read-only arrays of characters. It can be stored in memory that is not modifiable, leading to errors such as your when you attempt to modify it. That's why you should always use const char * when referring to string literals.
Use an array instead:
char sol[] = "hello";
I believe the recursive call to 'twstng()' at the bottom of the function has passed the new start and end indexes in the wrong order, given the names in the declaration (or else the declaration has them in the wrong order).
You mixed up your arguments.
Your function declaration says, that the first argument is the end and the second is the strt.
Your recursive call mixes them up.

Error when setting a character to a string in C

hey guys I need your help. I'm trying to extract a character from a string and set it as the 2nd element of an array of strings. Yet as usual C is giving me segmentation faults, Ive tried sprintf, strcpy, and still segmentation fault the code is:
int getwords(char *line, char *words[])
{
int nwords=2;
char *result= NULL;
char TABS[]="\t";
char spaces[]=" ";
char commas[]=",";
result = strtok(line,TABS);
words[1]=result[strlen(result)-1];//setting the 2nd element of the array to a char
result[strlen(result)-1]='\0';//removing the extracted char from the string
words[0]=result;//setting 1st element to the new modified word
printf("the opcode is:%s and the type is:%c\n",words[0],result[strlen(result)-1]);
return nwords;
}
e.g. If I give it "bye." it should return 2 and an array having 2 elements: 1st elem="bye" 2nd elem="."
I ran some tests and found out that the error is from the statement:
words[1]=result[strlen(result)-1];
Any help is welcom
Are you sure words is a modifiable string?
Literal strings are unmodifiable strings. For example: this gives segmentation fault:
char *test = "forty two";
test[6] = 'T'; /* make two uppercase */
You need to show how you call getwords and the definitions of the variables involved.
I'm guessing you're passing pointers to string literals.
There are two, perhaps four mistakes in the code below, I explain two of the mistakes in the code comments:
If we assume that "line", for the purposes of explaining what happens, is "hey\tthere"...
We also assume that "words" is an array of two pointers to char.
// Find the first token, in this case "hey", and return it in "result".
result = strtok(line,TABS); // NOTE: 'line' has been modified by the function!
// Take the last character in the returned statement, which is 'y', and
// copy it to the second cell in the 'words' array, however we are supposed
// to be copying a *pointer* to char there...
words[1]=result[strlen(result)-1];
Additionally, if "line" is static and can not be changed, the first line above will crash.
If "words" is not allocated or doesn't reference an array of at least two pointers to char, then the second line will crash.
If code execution gets past this point, any code that uses the "words" array will crash because the code will expect pointers, but is getting chars!

Resources